“This is the fourth day of my participation in the First Challenge 2022. For details: First Challenge 2022”

At the forefront of

What does it mean to implement mutually exclusive custom widgets?

In the use of Qt to do a strong interface beauty function, may encounter this problem: multiple controls mutually exclusive, similar to QRadiButton control, but not pure QRadioButton control, mutually exclusive may be a window, may also be a few buttons, and so on.

Here I just enumerated a simple mutex example, although simple, but contains a variety of pits, there is a need to dig friends can be small notes to remember, especially for Qt novice, or very necessary.

As you can see from the rendering, three custom widgets have been created, and when one of them is clicked, the other two background colors and text colors change and are selected.

Next, the function of the effect diagram is explained one by one, including knowledge points and pit records.

Function implementation

Implement a custom mutex widget. See if you have encountered any features or just need them.

knowledge

1. The Widget simulates the button’s four-state functions, including normal, Pressed, Focused, and Disabled

2: Set the background color and text content style of the Widget’s custom classes

3: How to make multiple widgets mutually exclusive

The problem

1: Why do custom Widget background color Settings not take effect?

Talk about this simple function for the above points and questions!

1.

Using the Widget to simulate the button’s four-state function requires the Widget’s own messages: mouse down, mouse in, and mouse out.

virtual void mousePressEvent(QMouseEvent *event); // Mouse down response message virtual void enterEvent(QEvent *event); Void leaveEvent(QEvent *event); // Mouse away response messageCopy the code

Does anyone ask, why is there no mouseMoveEvent message?

Answer: Using mouseMoveEvent messages directly in Qt does not trigger the mouse. SetMouseTracking (true) must be set to make the mouse trace event active in the current window.

Whether to set this function depends on the actual situation. In the current small demo, we are just converting images, there is no need to keep consuming resources in mouseMove.

(Side note: The mouse mosemove event in the MFC framework is directly available without special Settings)

Once the mouse enters the widget, it can be marked that the mouse remains active in the widget unless a leaveEvent message is triggered.

Mouse down response message
void QCustomWidget::mousePressEvent(QMouseEvent *event)
{
	this->SetWidgetStyle(Style_Down);
	QWidget::mousePressEvent(event);
}
Copy the code

Enumeration type currently used: mouse down response.

Mouse into widget response message
void QCustomWidget::enterEvent(QEvent *event)
{
	this->SetWidgetStyle(Style_Focus);
	QWidget::enterEvent(event);
}
Copy the code

Enumeration type currently used: mouse focused state, using enter messages instead of Mousemove messages.

If you log, you will notice that the trigger function is activated only once when the mouse enters the widget, but not when the mouse continues to move within the widget, greatly reducing message processing.

Mouse away from widget responds to message
void QCustomWidget::leaveEvent(QEvent *event)
{
	this->SetWidgetStyle(Style_Normal);
	QWidget::leaveEvent(event);
}
Copy the code

Enumeration type currently used: Mouse off state.

I’ve just shown you the simplest away setting. One thing to consider is how to display the widget if it is currently in the pressed state and the mouse is now away.

Do you have to show normal style?

The answer is definitely NO!

Although the mouse has been moved away, the selected state has changed from normal state to pressed state. In the application, we need to use a bool variable to record whether the widget is already selected. If so, we need to change the status to selected when the mouse leaves

The modifications are as follows:

if (m_bClickedState == true)
{
	this->SetWidgetStyle(Style_Down);
}
else
	this->SetWidgetStyle(Style_Normal);
Copy the code

2.

In the program, the simulated state is represented by the type of enumeration.

type instructions
Style_Normal The initial state of the mouse when no operation is performed
Style_Down The mouse is pressed in Wiget
Style_Focus Mouse movement status in the widget
Style_Disable The widget is currently in the ongoing state

The same content is displayed in each widget: number, text

Because only the presentation function, so all use QLabel control

QLabel *m_labNumber; // Number class pointer

QLabel *m_LabContent; // Content class pointer

Corresponding actual processing

Void QCustomWidget: : SetWidgetStyle (ENUM_WidgetStyle enumStyle) {/ / TODO: Set widget style QString qsStyle = "", gStyleNumberNormal = "", gStyleContentNormal = ""; Switch (enumStyle) {case Style_Normal: // set: qsStyle = "QWidget{background-color:#FFD700}"; // set: gStyleNumberNormal = "QLabel{color:#666666; font-family:Microsoft YaHei UI; font-size:14px; } QLabel{background-color: transparent}"; // Set: content style gStyleContentNormal = "QLabel{color:#666666; font-family:Microsoft YaHei UI; font-size:14px; } QLabel{background-color: transparent}"; } break; QsStyle = "QWidget{background-color:#FFB6C1}"; // set: gStyleNumberNormal = "QLabel{color:#0000FF; font-family:Microsoft YaHei UI; font-size:14px; } QLabel{background-color: transparent}"; // Set: content style gStyleContentNormal = "QLabel{color:#00FFFF; font-family:Microsoft YaHei UI; font-size:14px; } QLabel{background-color: transparent}"; } break; QsStyle = "QWidget{background-color:#FFF0F5}"; // set: gStyleNumberNormal = "QLabel{color:#98FB98; font-family:Microsoft YaHei UI; font-size:14px; } QLabel{background-color: transparent}"; // Set: content style gStyleContentNormal = "QLabel{color:#98FB98; font-family:Microsoft YaHei UI; font-size:14px; } QLabel{background-color: transparent}"; } break; QsStyle = "QWidget{background-color:#DCDCDC}"; // set: gStyleNumberNormal = "QLabel{color:#696969; font-family:Microsoft YaHei UI; font-size:14px; } QLabel{background-color: transparent}"; // Set: content style gStyleContentNormal = "QLabel{color:#696969; font-family:Microsoft YaHei UI; font-size:14px; } QLabel{background-color: transparent}"; } break; default: break; } this->setStyleSheet(qsStyle); m_labNumber->setStyleSheet(gStyleNumberNormal); m_labContent->setStyleSheet(gStyleContentNormal); }Copy the code

The background style varies according to the type. So you can take the code in, run it and see if it looks like what I showed you?

Ha ha! If you try it, this is what it looks like:

Why can only show text, my background? Where did you go? Didn’t I already set it?

Many Qt novices will encounter such problems here, so open a variety of search mode, try a variety of methods, sometimes change to change the right, also ignored the problem.

When creating a custom widget, the common method is to use a new instance. During the new process, we pass this as the parent pointer to the newly created window for the sake of hierarchy and parent-child relationships.

This happens once we pass the this pointer and do nothing in the custom Widget.

Subclasses inherit the style styles of the parent window.

Generally, there are two ways to handle this situation: override the paintEvent function for the current window and set it to not use the parent window style

For convenience, the second method is used when the background image drawn by the window is not complex:

this->setAttribute(Qt::WA_StyledBackground);
Copy the code

Setting the above code in the current custom Widget class constructor solves the problem of setting the background style but not seeing it.

3.

How do you implement mutual exclusion between widgets?

As anyone who has used the QRadioButton control knows, all it takes to set mutex is a simple set function.

For our custom widgets, there is no such function, and the mutex effect can only be manually set by the code and changed according to the selected and unselected state.

For example, if the custom Widget of Content 1 is selected, a message needs to be triggered in the mouse press response in the Widget to notify the outside world that the current custom Widget has been pressed and special processing is required

void QCustomWidget::mousePressEvent(QMouseEvent *event)
{
	this->SetWidgetStyle(Style_Down);
	emit Msg_SendClicked();
	QWidget::mousePressEvent(event);
}
Copy the code

Call the custom Widget’s parent class in response to the corresponding slot function for special handling.

conclusion

It’s easy to implement the custom Widget mutex effect here.

The implementation of the mutex operation is simple, but the most important thing to learn is how to set the background of the widget.

In many cases, this problem is most likely to occur when there are too many levels of nesting between the sub-window and the parent window, because it is best not to use the parent window style every time we create a new widget object.

I am a good citizen of China, focusing on C++ development program ape ~