Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1680720
  • 博文数量: 584
  • 博客积分: 13857
  • 博客等级: 上将
  • 技术积分: 11883
  • 用 户 组: 普通用户
  • 注册时间: 2009-12-16 09:34

分类: 嵌入式

2011-04-06 23:14:56

一 详细参考

  

 

Qt Stylesheets Tutorial

Stylesheets add spicy flavor to your boring Qt GUIs.

For a long time, Qt has allowed you to decorate your GUIs with CSS’ish style sheets. Inspired by the web, stylesheets are a great way to stylize your Qt GUI, but it seems that few people use them. In this tutorial, we’ll create an example dialog in Qt using Designer and stylesheets. This tutorial assumes that you can get around in Qt Designer, and that you understand a little about Qt layouts.

Step 1 Create a new empty form, named MyLoginForm.

Step 2 Add a QFrame to your form, and apply a vertical layout to your form (any layout will work actually: vertical, horizontal or grid). Give your form about 30 pixels of layout margin around its perimeter. Name the QFrame “mainFrame”. When dealing with stylesheets, it’s convenient to name your widgets in Designer, even if you don’t plan to use them by name in your code (we won’t be writing any code besides CSS in this tutorial).

Step 3 In Designer’s object inspector, right-click on the top-level entry in the tree (called “MyLoginForm”), and select “Change styleSheet…” from the menu. You’ll get a little editor dialog like this:

This is where we specify the style sheet for our form. You can put a style sheet on any widget in your form, but I prefer to do all my stylizing at the parent widget (“MyLoginForm” in this case). I prefer to do it this way because you’ll never have to go hunting to find your style sheet — it’s all in one place in your form. Since stylesheets cascade down to the child widgets, you can stylize any widget in your form from this point.

Side note: “CSS” stands for “Cascading Style Sheets”

Let’s type in some CSS into the style sheet editor, like this:

#MyLoginForm {
background: gray;
}

#mainFrame {
border: 3px solid gray;
border-radius: 40px;
background: white;
}

After clicking OK on the editor dialog, you should see this:

If your’s doesn’t look like this, you may have forgotten to change the parent widget’s name to “MyLoginForm” or the QFrame’s name to “mainFrame” (yes, capitalization does matter — Qt stylesheets are case sensitive). Or you may have mistyped something into the CSS dialog.

One cool feature is that you get to preview the style changes right as you make them. You don’t have to compile, save, or run anything. Designer does a very good job of showing your stylesheet changes live (WYSIWYG for you old-timers).

Let me explain what we just did. In CSS, a pound sign, ‘#’, in front of a name is how we stylize an individual widget by that name. In our example, #MyLoginForm identifies the parent widget (i.e., the background area). All we did there is give it a gray background with background: gray;.

For #mainFrame, we gave it a thick gray border, a white background, and rounded corners.

Step 4 Let’s add some widgets to make this dialog actually do something. Drag and drop a pair of QLineEdits, QLabels, and a single QPushButton on the form inside “mainFrame” and arrange them roughly like this:

Step 5 Now apply a grid layout to “mainFrame”. Just select “mainFrame” by clicking on it (taking care not to accidentally select one of the QLineEdits or QLabels instead). Then click the grid layout button in Designer’s toolbar (optionally, you can go to the menu bar and click “Form” -> “Lay Out in a Grid”, or just press Ctrl+5 for you keyboard hackers).

Then give your layout some margin. I used 50 pixels of margin and 15 pixels for both vertical and horizontal spacing.

This is what you should have now:

Step 6 Let’s stylize those boring QPushButton and QLineEdits. Add this to the style sheet for MyLoginForm:

QLineEdit {
padding: 1px;
border-style: solid;
border: 2px solid gray;
border-radius: 8px;
}

QPushButton {
color: white;
background-color: QLinearGradient( x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #88d, stop: 0.1 #99e, stop: 0.49 #77c, stop: 0.5 #66b, stop: 1 #77c);
border-width: 1px;
border-color: #339;
border-style: solid;
border-radius: 7;
padding: 3px;
font-size: 10px;
padding-left: 5px;
padding-right: 5px;
min-width: 50px;
max-width: 50px;
min-height: 13px;
max-height: 13px;
}

Notice that we didn’t use the pound sign this time. When you omit the pound sign, you are specifying a “class” of widgets to stylize instead of a single widget by name. So in this case, we stylized all widgets of type “QLineEdit” and “QPushButton” (and any widget that may inherit from those widgets too).

That gives the QPushButton a cool gradient look and rounds the edges of the QLineEdits, like this:

Step 7 Now let’s make that boring white background a gradient instead. Replace the “background: white;” line in the “#mainFrame” section with this instead:

background: QLinearGradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #eef, stop: 1 #ccf);

Now you should see this:

Step 8 Since stylizing is all about detail and little tweaks, let’s mess a bit with the label font and the background color by changing the background for “#MyLoginForm” to “background: white”, and adding this:

QLabel {
font-weight: bold;
font-size: 15px;
}

Now we get our finished product:

Isn’t it great how much you can do in Designer with style sheets? There are even things you can do with style sheets that can’t be done without writing lots of yucky C++ code. For example, you can change the border style of just a single side of a QFrame.

Oddities

There is one gotcha to keep in mind when using style sheets: Once you use a style sheet, it will often override other properties, like the “font” property or the “frameStyle” property. Keep this in mind when Designer changes properties you didn’t expect.

The other oddity with style sheets is that there’s no way to “include” external style sheet files into your widget’s style sheet. This means that you can’t have a common style sheet that gets applied to your entire application like you can in the web. I have a , but so far the Trolls haven’t done anything with it (to my knowledge). This would be immensely useful.

Cross Platform Note
A style sheet tutorial wouldn’t be complete without a comment on cross-platform issues. The dialog we just designed will look exactly the same on Linux, Windows, and Mac OS X because we stylized it so aggressively. If you want your widgets to look native on each platform, you should generally use style sheets sparingly, but if your goal is to have a consistent look across all platforms, style sheets are your best friend.

Conclusion

Now that I have discovered the power of style sheets in Qt, I use them whenever possible. What cool things have you done with Qt style sheets?

 

通过Qt4.2样式表定制程序外观

 

目录

1. 何为Qt样式表
2. 样式表语法基础
3. 方箱模型
4. 前景与背景
5. 创建可缩放样式
6. 控制大小
7. 处理伪状态
8. 使用子部件定义微观样式

    8.1. 相对定位
    8.2. 绝对定位

摘要

由于Qt样式表的引入,定制Qt部件的外观样式变得非常简单。 无论你是想仅仅修改一个现有部件的外观,还是想从零开始设计一套全新的界面风格, 现在都有了一种新的方法而不必再去继承并实现一个QStyle的子类。

1. 何为Qt样式表

Qt 样式表的思想很大程度上是来自于HTML的层叠式样式表(CSS), 通过调用QWidget::setStyleSheet()或QApplication::setStyleSheet(), 你可以为一个独立的子部件、整个窗口,甚至是整个个应用程序指定一个样式表。

样式表是通过QStyle的一个叫做QStyleSheetStyle的特殊子类来实现的。 这个特殊的子类实际上是其他的系统特定风格类的包裹类, 它会把通过样式表指定的自定义外观风格应用在底层的系统特定风格之上。

Qt 4.2包含了一个叫做stylesheet的例子来帮助你学习样式表, 这个例子自带了两个样式:Coffee和Pagefold。

上面的Coffee风格自定义了push button、frames和tooltip,但使用了下层的风格 (例如这里是Windows XP风格)来绘制checkbox,combobox和radio button。

Pagefold风格完全重新定义了对话框中使用的所有控件的外观,从而实现了一种独特的,平台无关的外观。

2. 样式表语法基础

Qt样式表与CSS的语法规则几乎完全相同,如果你已经了解了CSS,完全可以跳过本节。

一个样式表由一系列的样式规则构成。每个样式规则都有着下面的形式:

selector { attribute: value }

选择器(selector)部分通常是一个类名(例如QComboBox),当然也还有其他的语法形式。

属性(attribute)部分是一个样式表属性的名字,值(value)部分是赋给该属性的值。

为了使用方便,我们还可以使用一种简化形式:

selector1, selector2, ..., selectorM {
    attribute1: value1;
    attribute2: value2;
    ...
    attributeN: valueN;
}

这种简化形式可以同时为与M个选择器相匹配的部件设置N种属性。例如:

QCheckBox, QComboBox, QSpinBox {
    color: red;
    background-color: white;
    font: bold;
}

这个规则设置了所有的QCheckBox、QComboBox和QSpinBox的前景色、背景色和字体。

在线文档列出了每种部件支持的所有属性。在本文中,我们只使用最常见的几种通用属性。

3. 方箱模型

在样式表中,每个部件都被看作是一个由四个同心相似的矩形组成的箱体:空白(margin)、边框(border)、填充(padding)和内容(content)。对于一个平面部件——例如一个空白、边框和填充都是0像素的部件——而言,这四个矩形是完全重合的。

空白区域位于边框外,并且总是透明的。边框为部件提供了四周的框架,其border-style属性可以设置为一些内置的框架风格,如inset、outset、solid和ridge。填充在边框和内容区域之间提供了空白间隔。

4. 前景与背景

部件的前景色用于绘制上面的文本,可以通过color属性指定。背景色用于绘制部件的填充矩形,可以通过background-color属性指定。

背 景图片使用background-image属性定义,它用于绘制由background-origin指定的矩形区域(空白、边框、填充或内容)。背景 图片在矩形区域内的对齐和平铺方式可以通过background-position和background-repeat属性指定。

如果指定的背景图片具有alpha通道(即有半透明效果),通过background-color指定的颜色将会透过透明区域。这一功能可以使背景图片在多种环境下重复利用。

该例子中使用的样式表如下所示:

QFrame {
    margin: 10px;
    border: 2px solid green;
    padding: 20px;

    background-color: gray;
    background-image: url(qt.png);
    background-position: top right;
    background-origin: content;
    background-repeat: none;
}

在这个例子中,QFrame四周的空白、边框和填充值都是一样的。实际上margin属性可以在上下左右四个方向分别指定我们需要的不同值,例如:

QFrame {
    margin: 14px 18px 20px 18px;
}

同时,我们也可以分别指定margin-top、margin-right、margin-bottom、margin-left四个属性。

QFrame {
    margin-top: 14px;
    margin-right: 18px;
    margin-bottom: 20px;
    margin-left: 18px;
}

虽 然目前我们仅仅使用了QFrame作为例子,但是我们也可以同样的将这些属性应用于任何一个支持方箱模型的Qt部件,例如:QCheckBox、 QLabel、QLineEdit、QListView、QMenu、QPushButton、QTextEdit、和QToolTip。

5. 创建可缩放样式

在默认情况下,通过background-image指定的背景图片会自动重复平铺,以覆盖部件的整个填充矩形(即边框里面的那个区域)。如果我们想创建能够随着部件大小自动缩放而不是平铺的背景,我们需要设置一种称之为“边框图片”的东东。

“边框图片”可以通过border-image属性指定,它同时提供了部件的背景和边框。一个“边框图片”被分为九个部分(九宫格),有点向tic-tac-toe游戏的棋盘。

当一个部件的边框被填充时,四角的格子通常不会发生变化,而其余的五个格子则可能被拉伸或平铺以填充可用空间。

当指定一个“边框图片”时,除了图片本身,我们还必须指定用来分割九宫格的四条分割线。同时我们还必须指定非边角的格子是应该平铺还是拉伸,以及边框的宽度(用来确定边角格子的大小,防止边角被缩放变形)。

例如,下面的样式表定义了上图中的button:

QPushButton {
    border-width: 4px;
    border-image: url(button.png) 4 4 4 4 stretch stretch;
}

另外,“边框图片”还应该含有alpha通道,以使背景能够在边角处露出来。

6. 控制大小

min-width和min-height两个属性可以用来指定一个部件的内容区域的最小大小。这两个值将影响部件的minimumSizeHint(),并在布局时被考虑。

例如:

QPushButton {
    min-width: 68px;
    min-height: 28px;
}

如果该属性没有被指定,最小大小将从部件的内容区域和当前样式中继承。

7. 处理伪状态

部件的外观可以按照用户界面元素状态的不同来分别定义,这在样式表中被称为“伪状态”。例如,如果我们想在一个push button在被按下的时候具有sunken的外观,我们可以指定一个叫做 :pressed 的伪状态。

QPushButton {
    border: 2px outset green;
    background: gray;
}

QPushButton:pressed {
    border-style: inset;
}

下面是可用的伪状态列表:

表 1. 伪状态列表
伪状态    描述
:checked    button部件被选中
:disabled    部件被禁用
:enabled    部件被启用
:focus    部件获得焦点
:hover    鼠标位于部件上
:indeterminate    checkbox或radiobutton被部分选中
:off    部件可以切换,且处于off状态
:on    部件可以切换,且处于on状态
:pressed    部件被鼠标按下
:unchecked    button部件未被选中

8. 使用子部件定义微观样式

许多部件都包含有子元素,这些元素可以称为“子部件”。Spin box的上下箭头就是子部件最好的例子。

子 部件可以通过::来指定,例如QDateTimeEdit::up-button。定义子部件的样式与定义部件非常相似,它们遵循前面提到的方箱模型(即 它们可以拥有自己的边框、背景等),并且也可以和伪状态联合使用(例如QSpinBox::up-button:hover)。

下表列出了可用的子部件类型:

表 2. 子部件列表
子部件    描述
::down-arrow    combo box或spin box的下拉箭头
::down-button    spin box的向下按钮
::drop-down    combo box的下拉箭头
::indicator    checkbox、radio button或可选择group box的指示器
::item    menu、menu bar或status bar的子项目
::menu-indicator    push button的菜单指示器
::title    group box的标题
::up-arrow    spin box的向上箭头
::up-button    spin box的向上按钮

通 过指定subcontrol-position和subcontrol-origin属性,子部件可以被放置在部件箱体内的任何位置。并且,子部件的位置 还可以使用相对或绝对的方式进一步的调整。具体选择何种调整方式取决于子部件具有固定的大小,还是会随着父部件而变化。

8.1. 相对定位

相 对定位适合于子部件具有固定大小的情形(通过width和height指定子部件大小)。使用这种方式,子部件可以以相对于subcontrol- position和 subcontrol-origin属性定义的原始位置进行移动调整。使用left属性可以把子部件向右移,top属性可以把子部件向左移。

例如:

QPushButton::menu-indicator {
    image: url(menu_indicator.png);
    width: 13px;
    height: 13px;

    subcontrol-origin: padding;
    subcontrol-position: bottom right;
}

当按下按钮时,我们可以把菜单指示器从原来的位置向右下方移动几个像素来模拟按钮按下的状态。

QPushButton::menu-indicator:pressed {
    position: relative;
    top: 2px;
    left: 2px;
}

8.2. 绝对定位

绝对定位适合于子部件的位置随父部件的变化而变的情形。与前面的例子相同,subcontrol-origin定义了父部件箱体的参考矩形。子部件的矩形区域则可以随后通过相对于这个参考矩形四边的偏移量来定义。

QPushButton::menu-indicator {
    border: 2px solid red;

    subcontrol-origin: padding;
    position: absolute;
    top: 2px;
    right: 2px;
    bottom: 2px;
    left: 40px;
}

对于宽度或高度固定的子部件,subcontrol-position被用来说明其在subcontrol-origin指定矩形内的对其方式:

QPushButton::menu-indicator {
    image: url(menu_indicator.png);
    width: 13px;

    subcontrol-origin: padding;
    subcontrol-position: bottom right;
    position: absolute;
    top: 2px;
    bottom: 2px;
    right: 2px;
}

http://doc.qt.nokia.com/4.6/stylesheet-examples.html#customizing-qdockwidget

 

五 样式表使用

虽然Qt现在还不是特别完善,但它的跨平台性,界面重用性,已经表现出比mfc更强的、更好的性能,昨天写了qss样式表demo,但是在书上对样式表的使用,并不详细,初学者可能会遇到一些问题,今天对照官方代码,终于调通,简单记录如下:
    1、建立文本文件,写入样式表内容,更改文件后缀名为qss;
    2、在工程中新建资源文件*.qrc,将qss文件加入资源文件qrc中,此处注意prefix最好为"/",否则在调用qss文件时会找不到文件;
    3、通过传入路径\文件名的方式创建一个QFile对象,以readonly的方式打开,然后readAll,最后qApp->setStyleSheet就可以使qss生效。
    样式表的方式可以很方便的完成简单的贴图工作,而且效果也不错,简化了我以前在mfc上为了贴图,不得不重写控件类个工作,也使得美工可以很方便的修改生成的程序的颜色。
    当今年4月初的时候,NOKIA收购了Qt,并推出了Qt4.2,当时并没有太注意,而当mfc开发的界面不能满足我的时候,我才去研究这个新的技术。
    Qt很爽,因为是C++语言,所以看起来很快,预计在明年一月底,我就可以完全掌握,而且也因为是C++代码级跨平台,所以也获得了很高的执行效率。而它 生成控件的方式则比mfc上的资源文件好得多,mfc中的窗体资源全部在一个.src文件中,不利于重用,而Qt中每个窗体拥有自己的资源文件,并且和窗 体类是分开的,方便了重用。从此,我不在被局限于windows平台。
    我会研究一下如何在应用程序中完成widget部件的使用,因为那种透明、随意拖拽的自定义部件必将是下一代UI主流。
QApplication app(...);
QFile qss("stylesheet.qss");
qss.open(QFile::ReadOnly);
app.setStyleSheet(qss.readAll());
qss.close();

 

http://thesmithfam.org/blog/2009/09/10/qt-stylesheets-tutorial/

 

七 补记:对一个窗体或应用设置样式表,样式表的内容如果不特别制定属于那个或那类组件,其内容会应用到所有组件上;前一个的样式,会被后来的样式所覆盖。


阅读(1073) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~