Recent

Author Topic: Setting palettes for specific widgets/widget classes?  (Read 1288 times)

Zoë

  • New Member
  • *
  • Posts: 28
Setting palettes for specific widgets/widget classes?
« on: December 27, 2023, 08:06:38 pm »
What is the correct way to make a QPalette apply to all controls of a specific type? 

Using raw QT objects, I can use QApplication_setPalette(Palette, 'QCheckBox') or QWidget_setPalette(Widget, Palette);  Neither of those work for me for LCL backed controls, and modifying the TQtWidget(Handle).Palette.Handle doesn't seem to have an effect either.  I'm fine with creating any subclasses that would be required.

My specific goal is an application-wide dark mode palette, but at least with the Fusion style, checkboxes use QPaletteWindow for the square indicator frame, so they're almost invisible if the window itself is dark too.  I'd want to override just QPaletteWindow for QCheckBox, QListItem, and ideally TQtThemeServices.DrawElement(tbCheckBox*).

Since TQtThemeServices.DrawElement needs the palette applied using QStyleOption_setPalette, I don't see a way to do that with the existing ThemeServices API.  I could extract the relevant bits though.  Alternatively, would it make sense to query the palette from the context's parent at the top where it's initializing QPainter_setBackground?

For the LCL controls, the project I'm currently testing with is:

1) Create a new LCLQt5 project.
2) Add a TCheckbox and a TListView that has a single item and has Checkboxes := True.
3) Add an OnShow handler that creates a second form using the raw Qt API with matching controls, and sets the application/widget palettes appropriately:

Code: Pascal  [Select][+][-]
  1. procedure TForm1.FormShow(Sender: TObject);
  2. type
  3.   TQPaletteColorRole = QPaletteWindowText..QPaletteToolTipText;
  4. const
  5.   AppPalette: array[TQPaletteColorRole] of TColorRef = (
  6.     $eeeeee, $353535, $4b4b4b, $404040, $232323, $2c2c2c, $eeeeee, $0000ff,
  7.     $eeeeee, $282828, $353535, $2d2d2d, $a75824, $ffffff, $ff5500, $ff5500,
  8.     $353535, $000000, $2d2d2d, $eeeeee);
  9. var
  10.   Check: QCheckBoxH;
  11.   S: WideString;
  12. var
  13.   Palette: QPaletteH;
  14.   QColor: TQColor;
  15.   ColorRole: TQPaletteColorRole;
  16.   List: QListWidgetH;
  17.   Item: QListWidgetItemH;
  18.   RawWindow: QMainWindowH;
  19. begin
  20.   S := 'Raw QT';
  21.   // Create raw window
  22.   RawWindow := QMainWindow_Create;
  23.   QWidget_resize(RawWindow, Scale96ToScreen(220), Scale96ToScreen(150));
  24.   // Raw checkbox
  25.   Check := QCheckBox_Create(@S, RawWindow);
  26.   QWidget_setGeometry(Check, Scale96ToScreen(10), Scale96ToScreen(10),
  27.     Scale96ToScreen(200), Scale96ToScreen(20));
  28.   QWidget_show(Check);
  29.   // Raw listbox with checkboxes
  30.   List := QListWidget_Create(RawWindow);
  31.   QWidget_setGeometry(List, Scale96ToScreen(10), Scale96ToScreen(40),
  32.     Scale96ToScreen(200), Scale96ToScreen(100));
  33.   Item := QListWidgetItem_Create(@S, List);
  34.   QListWidgetItem_setFlags(Item, QListWidgetItem_flags(Item) or QtItemIsUserCheckable);
  35.   QListWidgetItem_setCheckState(Item, QtUnchecked);
  36.   Item := QListWidgetItem_Create(@S, List);
  37.   QListWidgetItem_setFlags(Item, QListWidgetItem_flags(Item) or QtItemIsUserCheckable);
  38.   QListWidgetItem_setCheckState(Item, QtChecked);
  39.   QWidget_show(List);
  40.   // Show raw window
  41.   QWidget_show(RawWindow);
  42.   // Set default application palette
  43.   Palette := QPalette_Create();
  44.   try
  45.     QColor := Default(TQColor);
  46.     for ColorRole := Low(ColorRole) to High(ColorRole) do
  47.     begin
  48.       ColorRefToTQColor(AppPalette[ColorRole], QColor);
  49.       QPalette_setColor(Palette, ColorRole, @QColor);
  50.     end;
  51.     QApplication_setPalette(palette);
  52.   finally
  53.     QPalette_Destroy(Palette);
  54.   end;
  55.   // Set control-specific palettes
  56.   Palette := QPalette_Create();
  57.   try
  58.     ColorRefToTQColor(clLime, QColor);
  59.     QPalette_setColor(Palette, QPaletteWindow, @QColor);
  60.     // Update for all QCheckBoxes and QListViews
  61.     QApplication_setPalette(Palette, 'QCheckBox');
  62.     QApplication_setPalette(Palette, 'QListView');
  63.     // Try to set for LCL checkbox?
  64.     QWidget_setPalette(TQtWidget(CheckBox1.Handle).Widget, Palette); // Doesn't work
  65.     QPalette_setColor(TQtWidget(CheckBox1.Handle).Palette.Handle, // Doesn't work
  66.       QPaletteWindow, @QColor);
  67.   finally
  68.     QPalette_Destroy(Palette);
  69.   end;
  70. end;
  71.  

With that code the raw QCheckBox and QListWidget have bright green borders, but the TCheckbox and TListView are both still dark-on-dark.

I'd prefer to avoid using stylesheets if possible, since that requires fully specifying the appearance of all of the checkbox states.  Overriding just QCheckbox::indicator's border color isn't enough.
« Last Edit: December 27, 2023, 09:39:30 pm by Zoë »

zeljko

  • Hero Member
  • *****
  • Posts: 1632
    • http://wiki.lazarus.freepascal.org/User:Zeljan
Re: Setting palettes for specific widgets/widget classes?
« Reply #1 on: December 28, 2023, 02:17:22 pm »
Palette can be setted up at application level (Fusion style), but control by control never worked for me,
I'm afraid that your problem can be fixed only via stylesheets.

 

TinyPortal © 2005-2018