Фон TLinkLabel на TPageControl - PullRequest
       28

Фон TLinkLabel на TPageControl

12 голосов
/ 28 августа 2009

Я пытаюсь использовать TLinkLabel на TPageControl, и я не могу найти способ заставить его использовать фон его родителя.

// Image removed because the website doesn't exist any more 
// and I can't find it anywhere... Sorry.

Как видите, прекрасный градиент родительской вкладки не сохраняется за текстом ссылки.

Мне бы хотелось, чтобы функциональность, состоящая из нескольких ссылок в текущем блоке текста (функция, предоставляемая TLinkLabel), и имеет фон родительского элемента, отображаемый за текстом.

TLinkLabel не имеет свойства ParentBackground. Я попытался создать производный класс, который добавляет csParentBackground к стилю элемента управления, но безрезультатно:

TMyLinkLabel = class (TLinkLabel)
public
  constructor Create(AOwner: TComponent); override;
end;

...

constructor TMyLinkLabel.Create(AOwner: TComponent); 
begin
  inherited;
  ControlStyle := ControlStyle - [csOpaque] + [csParentBackground]
end;

У кого-нибудь есть идеи?

Ответы [ 6 ]

7 голосов
/ 30 августа 2009

Нат, вы почти на месте с вашими изменениями ControlStyle из TLinkLabel. Кроме того, вам нужно убедиться, что родительский элемент стандартного статического элемента управления Windows (это то, что TLinkLabel) обрабатывает сообщение WM_CTLCOLORSTATIC правильно.

VCL имеет хороший механизм перенаправления, позволяющий элементам управления обрабатывать сообщения, отправляемые в качестве уведомлений их родительским окнам для себя. Используя это, можно создать полностью автономную метку прозрачной ссылки:

type
  TTransparentLinkLabel = class(TLinkLabel)
  private
    procedure CNCtlColorStatic(var AMsg: TWMCtlColorStatic);
      message CN_CTLCOLORSTATIC;
  public
    constructor Create(AOwner: TComponent); override;
  end;

constructor TTransparentLinkLabel.Create(AOwner: TComponent);
begin
  inherited;
  ControlStyle := ControlStyle - [csOpaque] + [csParentBackground];
end;

procedure TTransparentLinkLabel.CNCtlColorStatic(var AMsg: TWMCtlColorStatic);
begin
  SetBkMode(AMsg.ChildDC, TRANSPARENT);
  AMsg.Result := GetStockObject(NULL_BRUSH);
end;
4 голосов
/ 28 августа 2009

Обычно я ненавижу, когда люди предлагают сторонний компонент в качестве ответа, но я упомяну TMS THTMLabel как альтернативу тому, что вы хотите сделать. Он имеет свойство Transparent в TLabel и позволяет использовать HTML в качестве заголовка, поэтому вы можете создавать несколько ссылок в соответствии с вашим примером.

3 голосов
/ 28 августа 2009

Стили csParentBackground и csOpaque требуют взаимодействия с другими частями кода элемента управления. Простая установка их не будет иметь большого эффекта; в противном случае элемент управления, вероятно, уже имеет общедоступное свойство Transparent.

Вы можете посмотреть на TCustomLabel.Paint, чтобы увидеть, как он уважает стиль csOpaque Он проверяет этот стиль, читая его свойство Transparent, прежде чем раскрашивает фон:

if not Transparent then
begin
  Canvas.Brush.Color := Self.Color;
  Canvas.Brush.Style := bsSolid;
  FillRect(ClientRect);
end;

Стиль csParentBackground не влияет на TCustomLabel, поскольку этот стиль влияет только на оконные элементы управления; TCustomLabel происходит от TGraphicControl, а не TWinControl.

У меня нет TLinkLabel, поэтому я не могу взглянуть на его исходный код, чтобы выяснить, что ему нужно изменить. Если это потомок TGraphicControl, то он должен включать код, как я показал выше из TCustomLabel. Если он спустится с TWinControl, я бы вместо этого адаптировал код с TCustomStaticText. Это немного сложнее; он вызывает DrawParentBackground в ответ на уведомление cn_CtlColorStatic. Это также не рисует себя в коде Delphi. Элемент управления является оберткой для Win32 «статического» типа элемента управления.

TLinkLabel явно рисует фон безоговорочно. Чтобы это исправить, вам нужно переопределить метод Paint. Удаление функциональности (в данном случае рисование фона) трудно сделать с традиционным способом переопределения виртуальных методов, потому что вы не сможете вызвать унаследованный метод, чтобы получить весь окрашенный текст. Вместо этого вам, вероятно, придется скопировать и вставить реализацию базового класса, а затем добавить где-то условные части в середину.

1 голос
/ 28 августа 2009

Один из способов, который я могу придумать, - создать вспомогательный класс при реализации

type
  TLinkLabelHelper = class helper for TLinkLabel
  public
    procedure Add(const aBGColor: TColor; const S: string);
  end;

procedure TLinkLabelHelper.Add(const aBGColor: TColor; const S: string);
begin
  Color := aBGColor;
  Caption := S;
end;

Затем я создаю публичную

procedure AfterConstruction; override;

procedure Form_A.AfterConstruction;
begin
  inherited;
  LinkLabel1.Add(Self.Color, 'Hello World');
end;

Надеюсь, это сработает.

0 голосов
/ 28 августа 2009

Если ваш текст статичен, вы все равно можете сделать это с помощью меток. Выложите весь текстовый блок, включая слова, которые вы хотите в качестве ссылок. Установите метку как прозрачную. Затем удалите отдельные компоненты метки (также имеющие прозрачный вид), которые будут ссылками. Измените цвет на clNavy, стиль шрифта на fsunderline и курсор на crHand. Затем поместите метку над существующим текстом. Затем напишите обработчик onClick для каждой метки «ссылка», чтобы выполнить горячую ссылку.

Хотя это не оптимально, оно работает, если вы не хотите выделять текст жирным шрифтом и хотите, чтобы размер шрифта был одинаковым. Конечно, это не так хорошо работает, если блок является динамическим, так как вам придется вычислять положение меток ссылок в коде, что довольно сложно, если вы используете перенос слов. Если нет, вы можете использовать методы canvas.textwidth и canvas.textheight, чтобы определить необходимые позиции смещения для меток ссылок.

0 голосов
/ 28 августа 2009

Мой совет: используйте простой TLabel. У TLabel есть свойство Transparent - это то, что вам нужно. Установите курсор TLabels на crHandPoint (AFAIR это курсор ссылки), установите шрифт с синим подчеркиванием и напишите обработчик события OnClick, который откроет веб-браузер для перехода к указанному URL. Вы даже можете иметь один обработчик событий по умолчанию.

procedure OnClickOnMyLinkTLabels(Sender : TObject);
var
  Address : string;
begin
  if NOT (Sender is TLabel) then Exit;
  Address := (Sender as TLabel).Caption;
  ShellExecute(self.WindowHandle,'open',PChar(Address),nil,nil, SW_SHOWNORMAL);
end;

Редактировать

Если вы не хотите, чтобы в заголовке был адрес, вы можете использовать свойство Tag, чтобы получить адрес и установить для заголовка все, что вы хотите:

procedure OnClickOnMyLinkTLabels(Sender : TObject);
var
  Address : string;
begin
  if NOT (Sender is TLabel) then Exit;
  Address :=  GetAddresByTag( (Sender as TLabel).Tag );
  ShellExecute(self.WindowHandle,'open',PChar(Address),nil,nil, SW_SHOWNORMAL);
end;

Как вы будете реализовывать GetAddresByTag - ваш выбор. Самый простой - использовать массив строк:

//in your form defintion
   private
     FAddresses : array of string;

function GetAddresByTag(id : integer): string;
begin
  if (i<Low(FAddresses)) OR (I> High(FAddresses)) then
    raise EXception.Create('wrong id sent!');
  Result:= FAddresses[id];
end;
...