当前位置:网站首页>Qstype implementation of self drawing interface project practice (II)
Qstype implementation of self drawing interface project practice (II)
2022-07-02 17:11:00 【Jingchu idlers】
1. Preface
QT The link to the self - drawing technology series is as follows :
- 《QStyle Class Usage Summary ( One )》. Yes Qt Simple description of custom style , Yes QStyle And its related classes .
- 《QStyle Class Usage Summary ( Two )》. Yes QStyle And its related classes are described in detail .
- 《QStyle Class Usage Summary ( 3、 ... and )》. Yes QStyle Each of widget The hierarchical inheritance tree of elements is described in detail .
- 《QProxyStyle Brief introduction to usage 》. By a simple example , Demonstrated QProxyStyle Class usage .
- 《QStyle Realize the actual combat of self drawing interface project ( One )》 Understand the contents mentioned in the previous articles through the project practice , understand QStyle And the working mechanism of its subclasses in self drawing .
- 《QStyle Realize the actual combat of self drawing interface project ( Two )》 Understand the contents mentioned in the previous articles through the project practice , understand QStyle And the working mechanism of its subclasses in self drawing .
Before reading this article , Please read the related articles listed above first , Otherwise, there is no self drawing foundation , It is difficult to read this article .
2. Project description
Qt Bring your own example affine Medium ArthurStyle Class inherits from QCommonStyle, It realizes the function of drawing custom form parts , It is a good example of learning custom controls .
The storage path of the project is :Examples\Qt-XX.XX.XX\widgets\painting\affine
among XX.XX.XX by Qt Version number of , Such as :5.14.1. About the project and self drawing 、QStyle For analysis of irrelevant technical knowledge points, see 《Qt Examples And affine Engineering difficulties 、 Highlights summary 》 post , This blog only talks about the project and self drawing 、QStyle Relevant technical points .
3. Engineering analysis
This project is self drawn in arthurstyle.cpp File by ArthurStyle Class implements the .ArthurStyle Class member functions use PE_、CC_、SE_、PM_、CT_、SC_、CE_、 Identifier at the beginning , What do these identifiers mean , And draw the function of the component element represented by these identifiers drawPrimitive、drawComplexControl、drawControl Usage and meaning , Please refer to :《QStyle Class Usage Summary ( Two )》、《QStyle Class Usage Summary ( 3、 ... and )》 And Qt Assist, If you don't understand the meaning of these identifiers , It's hard to understand how self painting is achieved .
3.1.drawPrimitive function
drawPrimitive Function is used to draw graphic elements , That is, a certain one. widget Some part of , Such as :spin box Up and down arrow elements in . With PE_ The graphic elements represented by the beginning identifier are drawn by this function .
3.1.1.case Sentence of PE_IndicatorRadioButton
Qt Assist Yes PE_IndicatorRadioButton Explain the following :

It can be understood as : This identifier represents the small circle on the left of the radio button for checking and the surrounding rectangle outside the small circle . The logo is located case The statement is as follows :
case PE_IndicatorRadioButton:
if (const QStyleOptionButton *button = qstyleoption_cast<const QStyleOptionButton *>(option)) {
bool hover = (button->state & State_Enabled) && (button->state & State_MouseOver);
painter->save();
QPixmap radio;
if (hover)
drawHoverRect(painter, widget->rect());
if (button->state & State_Sunken)
radio = cached(":res/images/radiobutton-on.png");
else if (button->state & State_On)
radio = cached(":res/images/radiobutton_on.png");
else
radio = cached(":res/images/radiobutton_off.png");
painter->drawPixmap(button->rect.topLeft(), radio);
painter->restore();
}
break;
The first 2 That's ok : The program can enter PE_IndicatorRadioButton Where case sentence , The form part must be QRadioButton Type button . The following will option adopt qstyleoption_cast Cast to QStyleOptionButton, Because the form part at this time must be a button type , This transformation is sure to succeed .
The first 3 That's ok : If the radio button is available and the mouse is on the radio button , Call drawHoverRect function .drawHoverRect Function to draw the rounded rectangle when the mouse is on the radio button , So that users can visually perceive that the mouse is really floating on the radio box , That is, the following red box effect :

chart 1
Be careful : Pass to drawHoverRect The function of the first 2 Parameters should be widget->rect() That is, the rectangle occupied by the entire radio button , instead of button->rect or option->rect, The latter only represents the small circle on the left of the radio button for checking and the surrounding rectangle outside the small circle , That is, the rectangle represented by the red box below is not the rectangle occupied by the entire radio button :

chart 2
If drawHoverRect The function of the first 2 The rectangle of parameters is wrong , There will be no figure 1 Visual impact effect of mouse suspension .
The first 9~10 That's ok : When the mouse is pressed on the radio button , use radiobutton-on.png Pictures make up QPixmap Object passing drawPixmap Function drawing to graph 2 On the rectangle shown , To show the visual impact of the radio button being pressed .
The first 11~12 That's ok : When the radio button is checked , use radiobutton_on.png Pictures make up QPixmap Object passing drawPixmap Function drawing to graph 2 On the rectangle shown , To show the visual impact of the ticked radio button .
The first 13~14 That's ok : When the radio button is neither checked nor pressed , use radiobutton_off Pictures make up QPixmap Object passing drawPixmap Function drawing to graph 2 On the rectangle shown , To present the visual impact that the radio button is neither checked nor pressed .
3.1.2.case Sentence of PE_PanelButtonCommand
Qt Assist Yes PE_PanelButtonCommand Explain the following :

chart 3
combining 《QStyle Class Usage Summary ( 3、 ... and )》 post 2.2.1 Section pair push button Description of , Actually PE_PanelButtonCommand It can be simply understood as just a QPushButton Type button , The logo is located case The statement is as follows :
if (const QStyleOptionButton *button = qstyleoption_cast<const QStyleOptionButton *>(option)) {
bool hover = (button->state & State_Enabled) && (button->state & State_MouseOver);
painter->save();
const QPushButton *pushButton = qobject_cast<const QPushButton *>(widget);
Q_ASSERT(pushButton);
QWidget *parent = pushButton->parentWidget();
if (parent && qobject_cast<QGroupBox *>(parent)) {
QLinearGradient lg(0, 0, 0, parent->height());
lg.setColorAt(0, QColor(224,224,224));
lg.setColorAt(1, QColor(255,255,255));
painter->setPen(Qt::NoPen);
painter->setBrush(lg);
painter->setBrushOrigin(-widget->mapToParent(QPoint(0,0)));
painter->drawRect(button->rect);
painter->setBrushOrigin(0,0);
}
bool down = (button->state & State_Sunken) || (button->state & State_On);
QPixmap left, right, mid;
if (down) {
left = cached(":res/images/button_pressed_cap_left.png");
right = cached(":res/images/button_pressed_cap_right.png");
mid = cached(":res/images/button_pressed_stretch.png");
} else {
left = cached(":res/images/button_normal_cap_left.png");
right = cached(":res/images/button_normal_cap_right.png");
mid = cached(":res/images/button_normal_stretch.png");
}
painter->drawPixmap(button->rect.topLeft(), left);
painter->drawTiledPixmap(QRect(button->rect.x() + left.width(),
button->rect.y(),
button->rect.width() - left.width() - right.width(),
left.height()),
mid);
painter->drawPixmap(button->rect.x() + button->rect.width() - right.width(),
button->rect.y(),
right);
if (hover)
painter->fillRect(widget->rect().adjusted(3,5,-3,-5), QColor(31,127,31,63));
painter->restore();
}
break;The first 1 That's ok : The program can enter PE_PanelButtonCommand Where case sentence , The form part must be QPushButton Type button . The following will option adopt qstyleoption_cast Cast to QStyleOptionButton, Because the form part at this time must be a button type , This transformation is sure to succeed .
The first 2 That's ok : If the button is available and the mouse is on the button , be hover by true, Otherwise false.
The first 5~16 That's ok : Find the parent control of the button through the button , That is, outside the button QGroupBox, Create a gradient brush to fill the rectangle surrounding the button button->rect. Be careful :button->rect The coordinate is relative to its father QGroupBox Speaking of , namely
button->rect In order to QGroupBox Based on the coordinate system of , Therefore, you need to pass the following code :
painter->setBrushOrigin(-widget->mapToParent(QPoint(0,0)));The default coordinate origin of the brush ( The default value is based on the button coordinate system , And at the top left vertex of the button (0,0) It's about ) Turn to QGroupBox The origin of the brush coordinates in the coordinate system of .
The first 19~39 That's ok : First judge whether the button is pressed or checked , Depending on whether you press or not , Set different button maps . And then call drawPixmap Paste the map on the left and right parts of the button , call drawTiledPixmap Function to map the middle part of the button .
The first 40~41 That's ok : According to the first 2 Line determines whether the mouse hovers over the button , If it is suspended , Call fillRect function , Pass in QColor(31,127,31,63) Draw rectangle with brush , Because the color is different from that without suspension , In this way, users can have a visual impact .
3.1.3.case Sentence of PE_FrameGroupBox
Qt Assist Yes PE_FrameGroupBox Explain the following :
chart 4
combining 《QStyle Class Usage Summary ( 3、 ... and )》 post 2.2.9 Section pair Group Box Description of , Actually PE_FrameGroupBox Namely Group Box The outermost border of the panel . The logo is located case The statement is as follows :
if (const QStyleOptionFrame *group
= qstyleoption_cast<const QStyleOptionFrame *>(option)) {
const QRect &r = group->rect;
painter->save();
int radius = 14;
int radius2 = radius*2;
QPainterPath clipPath;
clipPath.moveTo(radius, 0);
clipPath.arcTo(r.right() - radius2, 0, radius2, radius2, 90, -90);
clipPath.arcTo(r.right() - radius2, r.bottom() - radius2, radius2, radius2, 0, -90);
clipPath.arcTo(r.left(), r.bottom() - radius2, radius2, radius2, 270, -90);
clipPath.arcTo(r.left(), r.top(), radius2, radius2, 180, -90);
painter->setClipPath(clipPath);
QPixmap titleStretch = cached(":res/images/title_stretch.png");
QPixmap topLeft = cached(":res/images/groupframe_topleft.png");
QPixmap topRight = cached(":res/images/groupframe_topright.png");
QPixmap bottomLeft = cached(":res/images/groupframe_bottom_left.png");
QPixmap bottomRight = cached(":res/images/groupframe_bottom_right.png");
QPixmap leftStretch = cached(":res/images/groupframe_left_stretch.png");
QPixmap topStretch = cached(":res/images/groupframe_top_stretch.png");
QPixmap rightStretch = cached(":res/images/groupframe_right_stretch.png");
QPixmap bottomStretch = cached(":res/images/groupframe_bottom_stretch.png");
QLinearGradient lg(0, 0, 0, r.height());
lg.setColorAt(0, QColor(224,224,224));
lg.setColorAt(1, QColor(255,255,255));
painter->setPen(Qt::NoPen);
painter->setBrush(lg);
painter->drawRect(r.adjusted(0, titleStretch.height()/2, 0, 0));
painter->setClipping(false);
int topFrameOffset = titleStretch.height()/2 - 2;
painter->drawPixmap(r.topLeft() + QPoint(0, topFrameOffset), topLeft);
painter->drawPixmap(r.topRight() - QPoint(topRight.width()-1, 0)
+ QPoint(0, topFrameOffset), topRight);
painter->drawPixmap(r.bottomLeft() - QPoint(0, bottomLeft.height()-1), bottomLeft);
painter->drawPixmap(r.bottomRight() - QPoint(bottomRight.width()-1,
bottomRight.height()-1), bottomRight);
QRect left = r;
left.setY(r.y() + topLeft.height() + topFrameOffset);
left.setWidth(leftStretch.width());
left.setHeight(r.height() - topLeft.height() - bottomLeft.height() - topFrameOffset);
painter->drawTiledPixmap(left, leftStretch);
QRect top = r;
top.setX(r.x() + topLeft.width());
top.setY(r.y() + topFrameOffset);
top.setWidth(r.width() - topLeft.width() - topRight.width());
top.setHeight(topLeft.height());
painter->drawTiledPixmap(top, topStretch);
QRect right = r;
right.setX(r.right() - rightStretch.width()+1);
right.setY(r.y() + topRight.height() + topFrameOffset);
right.setWidth(rightStretch.width());
right.setHeight(r.height() - topRight.height()
- bottomRight.height() - topFrameOffset);
painter->drawTiledPixmap(right, rightStretch);
QRect bottom = r;
bottom.setX(r.x() + bottomLeft.width());
bottom.setY(r.bottom() - bottomStretch.height()+1);
bottom.setWidth(r.width() - bottomLeft.width() - bottomRight.width());
bottom.setHeight(bottomLeft.height());
painter->drawTiledPixmap(bottom, bottomStretch);
painter->restore();The first 1 That's ok : The program can enter PE_FrameGroupBox Where case sentence , The form part must be PE_FrameGroupBox Group box border element of type . The following will option adopt qstyleoption_cast Cast to QStyleOptionFrame, Because the group box has a border , This transformation is sure to succeed .
The first 6~14 That's ok : Build a rectangle with rounded corners QPainterPath Drawing path class object clipPath, And set the crop region to clipPath, such GroupBox The outer border looks like a rounded rectangle .
The first 24~29 That's ok : take GroupBox Occupy the surrounding rectangle with a gradient brush lg Draw fill .
The first 32~38 That's ok : take GroupBox The corner occupied by the four endpoints of the bounding rectangle is used pixmap Picture filling 、 Mapping . That is, fill the figure 5 Number in 1 Areas shown in section .
The first 40~66 That's ok : take GroupBox The area occupied by the surrounding rectangle is not the corner formed by the four endpoints , And it is not used for rectangular body pixmap Picture filling 、 Mapping . That is, fill the figure 5 Number in 2 Areas shown in section .

chart 5
3.2.drawComplexControl function
drawComplexControl Function is used to draw complex controls , With CC The elements represented at the beginning are drawn by this function .
3.2.1.case Sentence of CC_Slider
Qt Assist Yes CC_Slider Explain the following :

chart 6
combining 《QStyle Class Usage Summary ( 3、 ... and )》 post 2.2.5 Section pair Slider Description of , Actually CC_Slider Namely Group Whole QSlider Control . The logo is located case The statement is as follows :
case CC_Slider:
if (const QStyleOptionSlider *slider = qstyleoption_cast<const QStyleOptionSlider *>(option)) {
QRect groove = subControlRect(CC_Slider, option, SC_SliderGroove, widget);
QRect handle = subControlRect(CC_Slider, option, SC_SliderHandle, widget);
painter->save();
bool hover = (slider->state & State_Enabled) && (slider->state & State_MouseOver);
if (hover) {
QRect moderated = widget->rect().adjusted(0, 4, 0, -4);
drawHoverRect(painter, moderated);
}
if ((option->subControls & SC_SliderGroove) && groove.isValid()) {
QPixmap grv = cached(":res/images/slider_bar.png");
painter->drawPixmap(QRect(groove.x() + 5, groove.y(),
groove.width() - 10, grv.height()),
grv);
}
if ((option->subControls & SC_SliderHandle) && handle.isValid()) {
QPixmap hndl = cached(":res/images/slider_thumb_on.png");
painter->drawPixmap(handle.topLeft(), hndl);
}
painter->restore();
}
break;The first 2 That's ok : The program can enter CC_Slider Where case sentence , The form part must be CC_Slider Type of composite control . The following will option adopt qstyleoption_cast Cast to QStyleOptionSlider, This transformation is sure to succeed .
The first 3~4 That's ok : By calling subControlRect function , obtain QSlider Control SC_SliderGroove、SC_SliderHandle The child control represented is the groove 、 The outer bounding rectangle occupied by the handle . About SC_SliderGroove、SC_SliderHandle What are the child controls represented 、 Please see 《QStyle Class Usage Summary ( 3、 ... and )》 post 2.2.5 Section pair Slider A description of and Qt Assist.
The first 8~12 That's ok : Check whether the mouse is hovering QSlider Above control . If so, call drawHoverRect Function to draw a light green rectangle with rounded corners , This will have a visual impact .
The first 14~19 That's ok : If the child control is SC_SliderGroove namely QSlider Groove sub control of composite control , Will slider_bar.png Attached to the SC_SliderGroove The outer bounding rectangle is on the appropriately reduced rectangle .
The first 20~23 That's ok : If the child control is SC_SliderHandle namely QSlider Handle sub control of composite control , Will slider_thumb_on.png Attached to the SC_SliderHandle On the outer bounding rectangle .
3.2.2 case Sentence of CC_GroupBox
Qt Assist Yes CC_GroupBox Explain the following :

combining 《QStyle Class Usage Summary ( 3、 ... and )》 post 2.2.9 Section pair GroupBox Description of , Actually CC_GroupBox Namely Group Whole QSlider Control . The logo is located case The statement is as follows :
if (const QStyleOptionGroupBox *groupBox
= qstyleoption_cast<const QStyleOptionGroupBox *>(option)) {
QStyleOptionGroupBox groupBoxCopy(*groupBox);
groupBoxCopy.subControls &= ~SC_GroupBoxLabel;
QCommonStyle::drawComplexControl(control, &groupBoxCopy, painter, widget);
if (groupBox->subControls & SC_GroupBoxLabel) {
const QRect &r = groupBox->rect;
QPixmap titleLeft = cached(":res/images/title_cap_left.png");
QPixmap titleRight = cached(":res/images/title_cap_right.png");
QPixmap titleStretch = cached(":res/images/title_stretch.png");
int txt_width = groupBox->fontMetrics.horizontalAdvance(groupBox->text) + 20;
painter->drawPixmap(r.center().x() - txt_width/2, 0, titleLeft);
QRect tileRect = subControlRect(control, groupBox, SC_GroupBoxLabel, widget);
painter->drawTiledPixmap(tileRect, titleStretch);
painter->drawPixmap(tileRect.x() + tileRect.width(), 0, titleRight);
int opacity = 31;
painter->setPen(QColor(0, 0, 0, opacity));
painter->drawText(tileRect.translated(0, 1),
Qt::AlignVCenter | Qt::AlignHCenter, groupBox->text);
painter->drawText(tileRect.translated(2, 1),
Qt::AlignVCenter | Qt::AlignHCenter, groupBox->text);
painter->setPen(QColor(0, 0, 0, opacity * 2));
painter->drawText(tileRect.translated(1, 1),
Qt::AlignVCenter | Qt::AlignHCenter, groupBox->text);
painter->setPen(Qt::white);
painter->drawText(tileRect, Qt::AlignVCenter | Qt::AlignHCenter, groupBox->text);
}
}
break;The first 3~5 That's ok : except Group box The title of the (SC_GroupBoxLabel) Outside ,Group box Other child controls of are drawn with default values , That is, call the parent class QCommonStyle Of drawComplexControl Function to draw .
The first 12~16 That's ok : according to Group box The length of the horizontal direction occupied by the title text and Group box Size information of the surrounding rectangle , stay Group box Occupy the middle of the rectangle 、 On the left 、 Map on the right .
The first 17~27 That's ok : Set the transparency of different brush colors and fine tune the rectangular position of the drawing title text several times to draw the title text , Finally, the title text is drawn with a white brush .
3.3.drawControl function
This function is very simple . The basic meaning is : If you draw a radio button 、pushbutton Button text , And the button text is empty , Then call the default value to draw , That is, call the parent class QCommonStyle Of drawControl function . If the radio button text is not empty , Align and draw the text in the center of the vertical direction ; If it is pushbutton Button text , The text is drawn vertically and horizontally centered .
边栏推荐
- C语言自定义函数的方法
- Youzan won the "top 50 Chinese enterprise cloud technology service providers" together with Tencent cloud and Alibaba cloud [easy to understand]
- ThreadLocal
- Use the API port of the bridge of knowledge and action to provide resources for partners to access
- Digital IC hand tearing code -- voting device
- L'explosion de John utilise l'encodage d'entrée par défaut: UTF - 8 Loaded 1 password Hash (bcrypt [blowfish 32 / 64 X3])
- 【Leetcode】13. 罗马数字转整数
- Talk about an experience of job hopping and being rejected
- Configure MySQL under Linux to authorize a user to access remotely, which is not restricted by IP
- Error when uploading code to remote warehouse: remote origin already exists
猜你喜欢

Just a coincidence? The mysterious technology of apple ios16 is even consistent with the products of Chinese enterprises five years ago!

剑指 Offer 22. 链表中倒数第k个节点

Interpretation of key parameters in MOSFET device manual

伟立控股港交所上市:市值5亿港元 为湖北贡献一个IPO

福元医药上交所上市:市值105亿 胡柏藩身价超40亿

Geoserver: publishing PostGIS data sources

LeetCode 2. Add two numbers

剑指 Offer 24. 反转链表

小鹏P7雨天出事故安全气囊没有弹出 官方回应:撞击力度未达到弹出要求

Go zero micro service practical series (VIII. How to handle tens of thousands of order requests per second)
随机推荐
MySQL port
linux下配置Mysql授权某个用户远程访问,不受ip限制
&lt; IV & gt; H264 decode output YUV file
Exploration and practice of integration of streaming and wholesale in jd.com
Connect Porsche and 3PL EDI cases
MOSFET器件手册关键参数解读
Easy language ABCD sort
john爆破出现Using default input encoding: UTF-8 Loaded 1 password hash (bcrypt [Blowfish 32/64 X3])
OpenPose的使用
TCP congestion control details | 2 background
綠竹生物沖刺港股:年期內虧損超5億 泰格醫藥與北京亦莊是股東
一年顶十年
你想要的宏基因组-微生物组知识全在这(2022.7)
Xiaopeng P7 had an accident on rainy days, and the airbag did not pop up. Official response: the impact strength did not meet the ejection requirements
C语言中sprintf()函数的用法
只是巧合?苹果iOS16的神秘技术竟然与中国企业5年前产品一致!
js删除字符串中的子串
Youzan won the "top 50 Chinese enterprise cloud technology service providers" together with Tencent cloud and Alibaba cloud [easy to understand]
Configure MySQL under Linux to authorize a user to access remotely, which is not restricted by IP
基于多元时间序列对高考预测分析案例