Make your Qt desktop program look more native (3): Custom style

Source: Internet
Author: User

We have repeatedly stressed that Qt uses its own method to draw components. However, we can also see that the Qt component performance is also different on different platforms. This is similar to Swing: Swing uses look and feel to show the appearance of components, and Qt is similar. The class used to draw the component appearance is QStyle. It should be noted that the style of the component is very complicated and cannot be fully explained here. If necessary, read the relevant documents carefully. In addition, this part involves a lot of classes, and functions are also very complex. Step-by-step is the best way to treat them. Unless necessary, we recommend that you do not touch the style part easily. Okay, the description also shows, and the scare is also scared. Next, let's start with the question. Custom style, as its name implies, is to achieve its own appearance. There are usually two implementation methods: first, rewrite the paintEvent () function of the widget; second, use the QStyle class. The two methods have different focuses: rewriting the paintEvent () function of the component can simply implement the style of a certain type of component, and inheriting the QStyle class can achieve consistency processing for all components, for example, convert all text in the program to red. First, let's take a look at rewriting the paintEvent () function. PaintEvent () is a function of QWidget, used to draw itself. A component is displayed on the screen by calling the paintEvent () function. Let's take a look at how complicated a component is. We need to use the implementation of the painting points and line functions provided by QPainter, so we can see the workload here. Of course, there is also a way to be lazy, that is, to replace paintEvent () with an image. We will not discuss this idea here, starting with the code. Take QPushButton as an example. Here, we create a button, which is displayed in the dashboard when clicked. To override the paintEvent () function, we must inherit the QPushButton class. The header file is very simple. I will skip it for the time being. Here I will only look at the paintEvent () function:

 
 
  1. void MyPushButton::paintEvent(QPaintEvent *) 
  2.     QStyleOptionButton option; 
  3.     option.initFrom(this); 
  4.     qDebug() << option.state; 
  5.     option.state |= isDown() ? QStyle::State_Sunken : QStyle::State_Raised; 
  6.     qDebug() << option.state; 
  7.     if (isDefault()) 
  8.         option.features |= QStyleOptionButton::DefaultButton; 
  9.     option.text = text(); 
  10.     option.icon = icon(); 
  11.  
  12.     QPainter painter(this); 
  13.     style()->drawControl(QStyle::CE_PushButton, &option, &painter, this); 
Although we mentioned above, we need to re-draw the entire component, but in fact, Qt provides us with a series of convenient functions to draw each component. This is useful when combining components. For example, a combo box is actually composed of a button and a downward triangle. So, I don't need to draw the entire combo box with a triangle, but I just need to use Qt to build and draw a button and a triangle. So here we also use a similar idea to let Qt draw a component. What we need to do is to modify the parameter and let it be drawn according to our parameter. What if I call the Qt component to draw a function? This plotting function is a member of the QStyle class. QWidget provides the style () function to return the current QStyle object. Then, we can draw through this object. Pay attention to the last line in the code above. We can see from here. The signature of this function is given below:
 
 
  1. virtual void QStyle::drawControl ( ControlElement element, const QStyleOption * option, QPainter * painter, const QWidget * widget = 0 ) const = 0; 
Although this is a pure virtual function, we can directly call the object returned by style (), similar to the Java interface. This is a typical style function call. Let's take a look at the definition of QStyle. The QStyle class provides many draw-hitting functions to draw the entire system component. This type of draw function generally has four parameters:
  • The first is an enum used to specify the element to be drawn. This enum may be different in different draw functions. For example, in drawControl (), QStyle: ControlElement refers to a component; in drawPrimitive (), QStyle: PrimitiveElement refers to the original component element of the component, for example, the focus box and check box;
  • The second is the QStyleOption object pointer. This object stores all the data information required for painter painting, such as the drawing size, coordinates, and text. Different elements may correspond to different subclass of QStyleOption, which can be found in this document;
  • The third is the QPainter object pointer. The system uses this painter for plotting;
  • The fourth is the QWidget Object Pointer, which is used to assist in drawing.
Back to the code, we can see that only the last one has the default value among the four parameters of the drawControl () function. That is to say, to call this function, we must prepare the parameter data. This is the work of the previous lines of code in paintEvent. The document shows that QPushButton requires QStyleOptionButton as the second parameter. Therefore, we create a QStyleOptionButton object. The initialization call initFrom () is to use this object to set an initial value. QStyleOption has many attributes. For example, QStyleOption: state indicates the current state. For example, if the button is pressed, that is, when isDown () returns true, we set the state to QStyle: State_Sunken, that is, concave, otherwise it is QStyle: State_Raised. In this way, the settings are complete. In addition, you also need to set other attributes as needed. For example, if isDefault () returns true, we need to set option. features so that the default effect can be drawn. The text and icon attributes are obtained through the button function. In this way, we can call the QStyle: drawControl () function to draw the button after setting the data to be drawn. Note that for the QFlags object, using the = value assignment is probably not the expected result. QFlags implements bitmap. If you simply use = to assign values, the values of the original bits are also clear. You can set the above option. state | = isDown ()? QStyle: State_Sunken: QStyle: State_Raised; change to option. state = isDown ()? QStyle: State_Sunken: QStyle: State_Raised. When calling the QStyle: drawControl () function, the first parameter can be found in the document. Here, the CE _ prefix actually means ControlElement. In this way, we have completed a simple Custom button. Although the code is simple, the general process has been shown. The rest is to read a large number of documents and carefully understand the use of each draw function to make a satisfactory custom component effect. The first custom component implementation mentioned above is simply mentioned here. Then let's look at the implementation of QStyle In the second method. In fact, we have used QStyle. We can also think that we still need to use various draw functions of QStyle, but here we do not simply call them, but inherit from them, replace the draw functions with our own version to customize the style. Although we can inherit QStyle directly, this is not a good idea. Because the QStyle class is very complex, almost all functions are pure virtual functions, which requires us to implement them one by one. Sometimes, we do not need to implement all the functions on our own, but simply make simple changes. Since version 4.6, Qt provides a dedicated class named QProxyStyle. All we need to do is inherit the QProxyStyle and overwrite the functions we are interested in. Take a look at the following simple example:
 
 
  1. class MyProxyStyle : public QProxyStyle 
  2.   public: 
  3.     void drawControl(ControlElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget) const; 
  4. }; 
  5.  
  6. void MyProxyStyle::drawControl(ControlElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget) const 
  7.     if(element == QStyle::CE_PushButtonLabel) { 
  8.         painter->drawText(option->rect, "fixed"); 
  9.     } else { 
  10.         QProxyStyle::drawControl(element, option, painter, widget); 
  11.     } 
MyProxyStyle overwrites the drawControl () function, and then determines that if it is a button label, the text "fixed" is drawn ". We can imagine that our QPushButton: setText () function has no function, because we didn't use this attribute during painting, and it won't be displayed. No matter whether you set or not, the text of all buttons will be fixed. If you want to use this style, you need to set it before running, for example:
 
 
  1. int main(int argc, char **argv) 
  2.     QApplication app(argc, argv); 
  3.     app.setStyle(new MyProxyStyle); 
  4.     MainWindow w; 
  5.     w.show(); 
  6.     return app.exec(); 
In this way, we can use our own style display component. As mentioned above, custom styles are a very complex topic and we cannot fully describe them here. However, because Qt provides this mechanism, we can easily implement custom styles.

This article is from the "bean space" blog, please be sure to keep this source http://devbean.blog.51cto.com/448512/471941

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.