Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: Общие вопросы > TCheckBox.AutoSize


Автор: shmelina 6.10.2010, 20:01
Добрый день.

Подскажите, как вычислить ширину TCheckBox?
TCheckBox создается динамически и там может быть разный текст. Требуется вычислить ширину контрола и задать ее в соответствии с текстом.
Я так понимаю, нужно сложить: ширина квадратика + расстояния между квадратиком и меткой + ширина метки.

Пробовал разобраться с исходниками TCheckBox, но ничего не понял. Буду очень признателен, за краткий алгоритм решения этой задачи. Предпочитаю удочку, а не рыбу.

Спасибо.

Автор: aleksh 6.10.2010, 20:05
удочку так удочку, есть функции вычисляющие длину слов, размер чекбокса без надписей можно посмотреть в дизайн-тайме, при создании чекбокса брать минимальную ширину + длину текста

Автор: shmelina 6.10.2010, 20:14
По удочкой я понимал - помочь разобраться как происходит отрисовка в исходниках компонента. Я так понимаю, что достаточно найти с какого места (Left) рисуется метка.

Функцию вычисления ширины текста можно взять у Canvas, метод TextWidth. Так?

Ширину квадратика в дизайне брать как-то не красиво. Не уверен, что при разных обстоятельствах (масштаб, ОС, темы...) она будет одинаковая. Да и расстояние между квадратиком и текстом тоже есть.

Автор: Frees 6.10.2010, 21:02
Цитата(shmelina @  6.10.2010,  23:14 Найти цитируемый пост)
Не уверен, что при разных обстоятельствах (масштаб, ОС, темы...) она будет одинаковая. Да и расстояние между квадратиком и текстом тоже есть.

GetSystemMetrics;

а разве у TCheckBox нет AutoSize?

Автор: shmelina 6.10.2010, 22:09
Цитата(Frees @  6.10.2010,  21:02 Найти цитируемый пост)
GetSystemMetrics;

Точно. Там вроде все что нужно есть. 
А сложно будет написать компонент-наследник, в котором будет свойство AutoSize? Я просто в исходниках не понял, как там отрисовка происходит. Знаний не хватает.
Цитата(Frees @  6.10.2010,  21:02 Найти цитируемый пост)
а разве у TCheckBox нет AutoSize? 

Нет. Я сам в шоке.

Я пока пошел простым путем, а там видно будет. Прошу помощи.
1. Нужно ли делать ReleaseDC? Судя по инету - нужно. Но с DC я плохо знаком.
2. Правильно ли я получаю DC? Вернее можно ли его получать вот так.
3. Правильно ли я освобождаю DC?
4. Нужно ли для Canvas указывать шрифт, если я его в CheckBox-е не меняю?

Код

var
  Canvas: TCanvas;
...
with TCheckBox(WinControl) do
begin
  Caption := Value;
  Canvas := TCanvas.Create;
  try
    Canvas.Handle := GetDC(Handle);
    try
      // Canvas.Font ?
      Width := Canvas.TextWidth(Caption) + 16;
    finally
      ReleaseDC(Handle, Canvas.Handle);
    end;
  finally
    Canvas.Free;
  end;
end;

Автор: XperT 7.10.2010, 00:49
А если посмотреть как у TLabel организован AutoSize и адаптировать под чекбокс?
Сейчас уже поздно, соображаю плохо, но вроде оно:
Код

procedure TCustomLabel.AdjustBounds;
const
  WordWraps: array[Boolean] of Word = (0, DT_WORDBREAK);
var
  DC: HDC;
  X: Integer;
  Rect: TRect;
  AAlignment: TAlignment;
begin
  if not (csReading in ComponentState) and FAutoSize then
  begin
    Rect := ClientRect;
    DC := GetDC(0);
    try
      Canvas.Handle := DC;
      DoDrawText(Rect, (DT_EXPANDTABS or DT_CALCRECT) or WordWraps[FWordWrap]);
      Canvas.Handle := 0;
    finally
      ReleaseDC(0, DC);
    end;
    X := Left;
    AAlignment := FAlignment;
    if UseRightToLeftAlignment then ChangeBiDiModeAlignment(AAlignment);
    if AAlignment = taRightJustify then Inc(X, Width - Rect.Right);
    SetBounds(X, Top, Rect.Right, Rect.Bottom);
  end;
end;

Автор: shmelina 7.10.2010, 11:00
Цитата(XperT @  7.10.2010,  00:49 Найти цитируемый пост)
А если посмотреть как у TLabel организован AutoSize и адаптировать под чекбокс?

Тут больше было дело не в отрисовке, а в определении ширины всего контрола. Ну тут уже подсказали про GetSystemMetrics, так что этот вопрос снят пока.

Все еще жду от вас ответов на вопросы по моему исходнику.

Спасибо.

Автор: Frees 7.10.2010, 12:47
Цитата(shmelina @  7.10.2010,  14:00 Найти цитируемый пост)
Все еще жду от вас ответов на вопросы по моему исходнику.

вряд ли твой исходник будет всегда корректно работать, например ты не учел Align. XperT правельно говорит, посмотри как это реализовано в других контролах.

Автор: shmelina 7.10.2010, 15:15
Цитата(Frees @  7.10.2010,  12:47 Найти цитируемый пост)
вряд ли твой исходник будет всегда корректно работать, например ты не учел Align. 

Align мне не страшен. В моей узкой задаче у этих контролов он не используется. Мне нужно было только правильно рассчитать ширину контролов, чтобы они не наезжали без причины на другие контролы. Прошу прощения, что не рассказал об этом подробнее.
Цитата(Frees @  7.10.2010,  12:47 Найти цитируемый пост)
XperT правельно говорит, посмотри как это реализовано в других контролах.

Покопавшись в исходниках CheckBox, я понял, что в этот раз я не осилю эту задачу. Посмотрите, пожалуйста, все ли корректно в исходнике с DC?

Автор: Frees 7.10.2010, 16:10
Цитата(shmelina @  7.10.2010,  18:15 Найти цитируемый пост)
Посмотрите, пожалуйста, все ли корректно в исходнике с DC?


Цитата(shmelina @  7.10.2010,  01:09 Найти цитируемый пост)
 Width := Canvas.TextWidth(Caption) + 16;

+ 16 на GetSystemMetrics; (наверняка есть такая метрика)

Автор: shmelina 7.10.2010, 16:15
Цитата(Frees @  7.10.2010,  16:10 Найти цитируемый пост)
+ 16 на GetSystemMetrics; (наверняка есть такая метрика)

Хорошо, посмотрю. А Font надо указывать для Canvas?

Автор: shmelina 7.10.2010, 18:32
В общем докладываю. Ширину картинки с галочкой нашел быстро, а вот расстояние между галкой и текстом так и не нашел. Перерыл пол-интернета, клянусь! Возможно знание английского недостаточно хорошее. Везде по-разному рекомендуют, где-то Canvas.TextWidth(' '), где-то GetSystemMetrics(SM_CXEDGE) * 2, где-то GetSystemMetrics(SM_CXBORDER) * 4. Методом тыка понял, что подходит число 4. Последние два варианта его же и показывают.

Я выше спрашивал про Canvas.Font - его указывать не обязательно, если он совпадает у CheckBox и у DC. Проверил на разных шрифтах - все работает правильно. Масштаб шрифтов проверять нет уже сил.

Время поиска решения этой задачи превысило все мыслимые пределы. По этому пока останусь на этом варианте:
Код

{ Возможно вместо 4 можно использовать
   GetSystemMetrics(SM_CXEDGE) * 2 или
   GetSystemMetrics(SM_CXBORDER) * 4 или что-то другое }
Width := GetSystemMetrics(SM_CXMENUCHECK) + 4 + Canvas.TextWidth(Caption);


Всем спасибо за помощь. Как всегда выручили.

Автор: zubpost 4.6.2019, 19:54
Я сделал так - Создал хелпер.
Добавляете этот юнит к поекту. И после того как задали текст вызываете процедуру TCheckBox.correctSize. 


Код

unit uCheckBoxHelper;

interface

uses
  Vcl.StdCtrls, Vcl.Graphics, Winapi.Windows;

type
  TCheckBoxHelper = class helper for TCheckBox
  public
    procedure correctSize;
  end;

implementation

{ TCheckBoxHelper }

procedure TCheckBoxHelper.correctSize;
var
  canvas: TCanvas;
  DC: HDC;
begin

  canvas := TCanvas.Create;
  DC := GetDC(0);
  try
    canvas.Handle := DC;
    canvas.Font:=self.Font;
    self.Width:=GetSystemMetrics(SM_CXMENUCHECK) + 4 + Canvas.TextWidth(Caption);
  finally
    ReleaseDC(0, DC);
  end;
  canvas.Free;
end;

end.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)