Подтвердить что ты не робот

Фон TLinkLabel на TPageControl

Я пытаюсь использовать 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;

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

4b9b3361

Ответ 1

Нат, вы почти там с вашими изменениями в 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;

Ответ 2

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

Ответ 3

Стили 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. Удаление функциональности (в данном случае - фоновое рисование) сложно сделать с традиционным способом переопределения виртуальных методов, потому что вы не сможете вызвать унаследованный метод, чтобы получить весь текст, нарисованный. Вместо этого вам, вероятно, придется скопировать и вставить реализацию базового класса, а затем добавить условные части в середине где-нибудь.

Ответ 4

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

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;

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

Ответ 5

Мой совет: используйте простой 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;

Edit

Если вы не хотите иметь адрес в своем заголовке, вы можете использовать свойство 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;

Ответ 6

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

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