如何更改QtDesigner中QDateEdit对象中箭头的外观(例如颜色)?

huangapple go评论70阅读模式
英文:

How can I change the appearance (e.g. colour) of the arrows in the QDateEdit object in QtDesigner?

问题

我有一个关于更改QDateEdit对象外观的问题。我通常可以更改诸如边框、边框半径和左边距等参数,但至少无法更改箭头的颜色。有没有办法解决这个问题?

QDateEdit QAbstractSpinBox::up-arrow {
    background-color: white;
    border: none;
}

QDateEdit QAbstractSpinBox::down-arrow {
    background-color: white;
    border: none;
}

QDateEdit QAbstractSpinBox {
    border: none;
}

QDateEdit {
    border: 2px solid #6D9886;
    border-radius: 8px;
    padding-left: 10px;
}

根据这段代码,以下操作应该会发生:

  • 边框颜色更改(已发生)
  • 边框宽度更改(已发生)
  • 箭头的颜色更改(未发生)
  • 箭头边框更改(未发生)

如何更改QtDesigner中QDateEdit对象中箭头的外观(例如颜色)?

英文:

I have a problem with changing the appearance of the QDateEdit object. I can normally change parameters such as border, border radius and padding left, but I cannot change at least the colour of the arrows. Is there any way to fix this?

QDateEdit QAbstractSpinBox::up-arrow {
    background-color: white;
    border: none;
}

QDateEdit QAbstractSpinBox::down-arrow {
    background-color: white;
    border: none;
}

QDateEdit QAbstractSpinBox {
    border: none;
}

QDateEdit {
    border: 2px solid #6D9886;
    border-radius: 8px;
    padding-left: 10px;
}

It seems to me that the following actions follow from this code:
the border colour changes (what happens)
the width of the border changes (what happens)
the colours of the arrows change (which does not happen)
arrow borders change (which does not happen)

如何更改QtDesigner中QDateEdit对象中箭头的外观(例如颜色)?

答案1

得分: 3

以下是您要翻译的内容:

"有两个在处理QSS(Qt样式表)时需要注意的重要方面。

第一个是,在处理复杂的小部件时,应始终记住以下关于子控件的说明:

> 注意: 对于复杂的小部件,如QComboBox和QScrollBar,如果自定义了一个属性或子控件,那么所有其他属性或子控件也必须进行自定义。

这意味着,每当复杂的小部件具有可能改变子控件外观的QSS规则时,所有该控件的属性都应该被正确地设置。

<hr>

不幸的是,您的样式表存在根本性的缺陷。

最重要的是,基于以下内容的规则无效

QDateEdit QAbstractSpinBox[whatever] {
   ...
}

原因是您正在使用"后代选择器":

选择器 示例 说明
后代选择器 <pre>QDialog QPushButton</pre> 匹配QDialog的后代(子代,孙代等)中的所有QPushButton。

上面的意思是,您正在为可能是QDateEdit的子代的任何QAbstractSpinBox设置规则:这是错误的,因为QDateEdit 继承自QAbstractSpinBox,所以旋转按钮就是QDateEdit,而不是它的子代。

<br>
然后,还有有关指定所有属性的问题。

不幸的是,如上所述,每当您设置影响其几何形状的复杂小部件规则时,您需要指定与其子控件相关的所有属性。而且,由于设置上述属性会清除QAbstractSpinBox箭头按钮的显示,因此您必须明确设置它们。

正如示例所示,惯例是为箭头图标指定图像文件,这导致了第二个问题。

QSS是使用原始CSS 2.1实现开发的,那时计算机屏幕上的像素密度并不那么重要。虽然Qt通常能够在高DPI屏幕上转换px单位,但这并不总是考虑到与文本显示的关系,如果屏幕使用字体缩放,这就非常重要。即使在指定图像资源时也是如此:除非您提供可缩放的图像(即:svg文件),否则图标可能具有错误的大小(几乎看不见或非常大),即使在这种情况下,样式表也应根据这些方面进行正确的自定义和测试。

因此,只有三种可能性:

  1. 仅使用默认外观(可用性比外观重要得多!);
  2. 提供(并进行适当测试)用于箭头的自定义可缩放图像;
  3. 忽略与DPI相关的任何方面,并使用下面的技巧;

第三种可能性使用了一种常见的技巧(参见相关帖子), 它可以作为箭头图标使用:创建一个空内容并使用虚假的CSS边框,箭头是唯一可见的边框,方向与箭头相反。

请注意,您必须考虑以下几个方面:

  • 默认的"透明"边框必须使用rgba(255, 255, 255, 0)设置,而不是transparent(它的RGB组件为0,不会覆盖其他边框);
  • QSS要求所有小部件的长度必须以px单位表示,这意味着您可能会遇到如上所述的问题(因此,不能保证在所有地方都能正常工作);
  • 为确保QSS的正确管理,小部件应使用fusion样式:dateEdit.setStyle(QStyleFactory.create(&#39;fusion&#39;))
  • 箭头颜色应与小部件背景一致;根据您的代码和截图,不清楚"灰色"背景是否是手动/程序设置的,但您绝对不能忽视这一点,否则将使重要的UI元素对用户来说几乎或完全不可见;考虑在CSS中使用palette()语法。

以下是可用于获得所需结果的经过校正和更新的QSS:

QDateEdit {
    border: 2px solid #6D9886;
    border-radius: 8px;
	padding-left: 10px;
}

QDateEdit::up-button, QDateEdit::down-button {
	border: none;
	padding-right: 5px;
}

QDateEdit::up-button {
	subcontrol-position: top right;
}

QDateEdit::down-button {
	subcontrol-position: bottom right;
}

QDateEdit::up-arrow, QDateEdit::down-arrow {
	border: 5px solid rgba(255, 255, 255, 0);
	width: 0;
	height: 0;
}

QDateEdit::up-arrow {
	border-top: none;
	border-bottom-color: white;
}

QDateEdit::down-arrow {
	border-bottom: none;
	border-top-color: white;
}

<sup>考虑到上述建议,请查看下面的更新。</sup>

我强烈建议您查看QSS的示例、[参考](https://doc.qt.io/qt-5/

英文:

There are two important aspects when dealing with QSS (Qt Style Sheets).

The first one is that, when dealing with complex widgets, one should always remember the following note about sub controls:

> Note: With complex widgets such as QComboBox and QScrollBar, if one property or sub-control is customized, all the other properties or sub-controls must be customized as well.

This means that, whenever a complex widget has a QSS rule that might alter sub-control appearance, ALL properties of that control should be properly set.

<hr>

Unfortunately, your style sheet has fundamental flaws.

Most importantly, the rules based on the following are not valid:

QDateEdit QAbstractSpinBox[whatever] {
   ...
}

The reason is that you're using the "Descendant Selector":

Selector Example Explanation
Descendant Selector <pre>QDialog QPushButton</pre> Matches all instances of QPushButton that are descendants (children, grandchildren, etc.) of a QDialog.

The above means that you're setting a rule for any QAbstractSpinBox that would be a child of a QDateEdit: that's wrong, because QDateEdit inherits from QAbstractSpinBox, so the spinbox is the QDateEdit, not its child.

<br>
Then, there's the issue about specifying all properties.

Unfortunately, as said above, whenever you set a complex widget rule that affects its geometry, you need to specify all properties related to its sub controls. And, since setting the above properties will clear the display of the QAbstractSpinBox arrow buttons, you have to explicitly set them.

As the examples show, the convention is to specify image files for the arrow icons, which leads us to the second problem.

QSS were developed with the original CSS 2.1 implementation, a time in which pixel density was not that important in computer screens.
While Qt is normally capable of converting px units in High DPI screens, this doesn't always consider the relation with text display, which is extremely important if the screen uses font scaling. This is also valid when specifying image resources: unless you provide scalable images (aka: svg files), the icons might have wrong sizes (almost invisible, or extremely big), and even in that case, the style sheet should be properly customized and tested considering these aspects.

So, there are only three possibilities:

  1. just stick to the default appearance (usability is much more important than appearance!);
  2. provide (and properly test) custom scalable images for the arrows;
  3. ignore any DPI related aspect, and use the below trick;

The 3rd possibility uses a common trick (see this related post) that can be used as arrow icons: create an empty content and use fake CSS borders, with the "arrow" being the only visible border opposite to the arrow direction.

Note that you must consider the following aspects:

  • the default "transparent" border must be set with rgba(255, 255, 255, 0) and not transparent (which is has 0-rgb components and won't overlay the other borders at all);
  • QSS requires that all widget lengths must be in px units, meaning that you might have issues as explained above (so, no, it's not guaranteed to work everywhere);
  • in order to ensure proper QSS management, the widget should use the fusion style: dateEdit.setStyle(QStyleFactory.create(&#39;fusion&#39;));
  • the arrow color should be consistent with the widget background; from your code and screenshot it is not clear if the "gray" background is manually/programmatically set, but you can never ignore that aspect, otherwise you will make important UI elements almost or completely invisible to the user; consider using the palette() syntax in CSS.

Here is the corrected and updated QSS that could be used to get the wanted result:

QDateEdit {
    border: 2px solid #6D9886;
    border-radius: 8px;
	padding-left: 10px;
}

QDateEdit::up-button, QDateEdit::down-button {
	border: none;
	padding-right: 5px;
}

QDateEdit::up-button {
	subcontrol-position: top right;
}

QDateEdit::down-button {
	subcontrol-position: bottom right;
}

QDateEdit::up-arrow, QDateEdit::down-arrow {
	border: 5px solid rgba(255, 255, 255, 0);
	width: 0;
	height: 0;
}

QDateEdit::up-arrow {
	border-top: none;
	border-bottom-color: white;
}

QDateEdit::down-arrow {
	border-bottom: none;
	border-top-color: white;
}

<sup>Considering the above suggestion, please take a look at the update below.</sup>

I strongly recommend you to look at the QSS examples, reference and syntax, and also take your time (a lot of it) to make experiments and tests in order to understand how the above works. Also, never underestimate the studying of source code (starting with this code browser, which is wonderfully done and extremely educational).

<hr>

Finally, remember that, as powerful and extensible (and, to be honest, not always reliable) the QSS framework is, it should always be used with care and awareness. The QtWidget module was created and intended for usage in a period where screen visualization was quite standardized, and the main priority was always usability and full widget visibility, as the UI didn't need to be fancy if it wasn't usable (actually, that should be a fundamental rule of thumb, but that's a bit off topic).

Making the UI "good looking" is fine, but never lose the usability aspect, which should always have absolute priority. People won't care if the UI is fancy, if they're not able to properly use it.

A more appropriate QSS

Since the stylesheet should always consider the state of interactive elements and, as much as possible, the current palette, you should consider the following aspects:

  • the widget should always try to use the default palette (the one of the current QApplication, meaning the one retrieved from the OS or that explicitly set using QApplication.setPalette()), otherwise the contents of the widget might become invisible;
  • interactive elements should always show hints to the user: the most important aspect is the enabled/disabled state of the widget, but mouse hover or window active state should be considered as well;

With the above in mind, I'll suggest the following QSS, assuming that a proper QSS or QPalette was set on the QApplication. Most importantly, even considering the extensible nature of QSS features, the application QPalette is of extreme importance. So, unless you are going to explicitly set an extensive QSS rule that is application-wide, you should primarily set a basic QPalette for the application and eventually alter its colors based on that assumption.

As long as a proper QPalette is set (including appropriate colors for roles such as QPalette.Base and QPalette.Text), the following QSS will be valid and user intuitive:

QDateEdit {
    border: 2px solid #6D9886;
    border-radius: 8px;
    padding-left: 10px;
}

QDateEdit::up-button, QDateEdit::down-button {
    border: none;
    padding-right: 5px;
}

QDateEdit::up-button {
    subcontrol-position: top right;
}

QDateEdit::down-button {
    subcontrol-position: bottom right;
}

/* now, the magic begins */

QDateEdit::up-arrow, QDateEdit::down-arrow {
    /* a default color for the &quot;border&quot; (aka, the arrow) */
    border: 5px solid palette(button-text);

    /* right and left borders will be transparent */
    border-left-color: rgba(255, 255, 255, 0);
    border-right-color: rgba(255, 255, 255, 0);

    /* basic &quot;null&quot; size as above */
    width: 0;
    height: 0;
}

/* set up the up arrow states */

QDateEdit::up-arrow {
    /*
        we want to show the &quot;down border&quot; alone, so we make the 
        opposite one (the top) invisible and **empty**
    */
    border-top: none;
}

QDateEdit::up-arrow:hover {
    border-bottom-color: palette(highlight);
}

QDateEdit::up-arrow:pressed {
    border-bottom-color: palette(text);
}

QDateEdit::up-arrow:disabled, QDateEdit::up-arrow:off {
    /*
        use the &quot;mid&quot; color role as a disabled/invalid arrow
        state; since this rule is stated *after*, it will take
        precedence in case it matches;
    */
    border-bottom-color: palette(mid);
}

/*
    set up the down arrow states, similarly to the above, but
    using the opposite border when relevant.
*/

QDateEdit::down-arrow {
    border-bottom: none;
}

QDateEdit::down-arrow:hover {
    border-top-color: palette(highlight);
}

QDateEdit::down-arrow:pressed {
    border-top-color: palette(text);
}

QDateEdit::down-arrow:disabled, QDateEdit::down-arrow:off {
    border-top-color: palette(mid);
}

huangapple
  • 本文由 发表于 2023年6月8日 02:05:00
  • 转载请务必保留本文链接:https://go.coder-hub.com/76425970.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定