简体   繁体   中英

Horizontally center radio button label

I am using radio buttons to create a vertical tabs effect. I got the entire thing to work but I am stuck in doing something that I am pretty sure to be easy.

In this part of the code I go through a list of tabs name and generate radio buttons for each:

def _init_vertical_tabs(self, layout, row):
    """Initialize vertical tabs"""
    tabs_widget = QtWidgets.QWidget()
    tabs_widget.setObjectName("tabs")
    vertical_tabs_layout = QtWidgets.QVBoxLayout()
    vertical_tabs_layout.setSpacing(0)
    vertical_tabs_layout.setContentsMargins(0, 0, 0, 0)
    vertical_tabs_layout.setAlignment(QtCore.Qt.AlignCenter)
    tabs_widget.setLayout(vertical_tabs_layout)
    layout.addWidget(tabs_widget, row, 0, len(self.tabs), 1)

    tabs_widget.setMinimumHeight(self.parent_height)
    tabs_widget.setMinimumWidth(self.parent_width*0.15)
    tabs_widget.setMaximumHeight(self.parent_height)
    tabs_widget.setMaximumWidth(self.parent_width*0.15)

    tab_to_widget = dict()
    for tab in self.tabs:
        tab_button = self._create_tab(tab, vertical_tabs_layout, self.parent_width*0.15, self.parent_height/len(self.tabs),)
        tab_to_widget[tab] = tab_button

def _create_tab(self, tab, layout, width, height):
    """Basic method to create a fake tab"""
    button = QtWidgets.QRadioButton(tab)
    button.setContentsMargins(0, 0, 0, 0)
    l = lambda tab_name = tab: self.toggle_visibility_tabs(tab_name)
    button.clicked.connect(l)

    button.setMinimumHeight(height)
    button.setMinimumWidth(width)
    button.setMaximumHeight(height)
    button.setMaximumWidth(width)

    layout.addWidget(button)

Then I applied some css:

    QWidget#tabs{
  color: #ffffff;
  background-color: #005073;
  border: 0px solid #e54d42;
  text-align: center;
}

QWidget#tabs QRadioButton{
  color: #ffffff;
  font-weight: 400;
  font-size: 20pt;
  border-radius: 0px;
  background-color: #003850; /*QLinearGradient(x1:0, y1:0, x2:0, y2:1, stop:0 #003850, stop:0.5 #005073, stop:1 #003850);*/
  margin: 0px;
  font-family: Arial, Helvetica, sans-serif;
  text-align: center;
}

QWidget#tabs QRadioButton#Validator{
  border-bottom-left-radius: 60px;
  border-left: none;
}

QWidget#tabs QRadioButton::indicator{
  width: 0px;
  height: 0px;
  border-radius: 0px;
  border: 1px solid #e54d42;
  border-top: none;
  border-right: none;
  border-left: none;
  font-family: Arial, Helvetica, sans-serif;
  text-align: center;
}

QWidget#tabs QRadioButton:hover, QWidget#tabs QRadioButton:selected,  QWidget#tabs QRadioButton:checked{
  border-left: 30px solid #e54d42;
  color: #e54d42;
}

And the result is: 在此处输入图片说明

I would like to have the text in the center instead, I tried to use size policies and I got to this: 在此处输入图片说明

But this is not quite what I wanted, first the radio button labels are still left-aligned and since the radio is shorter the red border of selected ones is obviously not in the left anymore. Can someone tell me if there is an easy way of achieving this either in the css or in the python code? I tried the text-align as well but didn't work either.

Thanks!

Using stylesheets alone for this is almost impossible. I'd suggest you to mix stylesheets and custom painting.

First of all, edit the stylesheet ensuring that all colors for your radio buttons are set to transparent .

Then, create a subclass of QRadioButton, which both draws the button by calling the base class implementation and draws the text with the specified color and font.

class CustomRadio(QtWidgets.QRadioButton):
    def paintEvent(self, event):
        # draw the widget as paintEvent normally does
        super().paintEvent(event)

        # create a new painter on the widget
        qp = QtGui.QPainter(self)
        # create a styleoption and init it with the button
        opt = QtWidgets.QStyleOptionButton()
        self.initStyleOption(opt)

        # now we can know if the widget is hovered and/or checked
        if opt.state & (QtWidgets.QStyle.State_MouseOver | QtWidgets.QStyle.State_On):
            # if it is, set the color accordingly
            qp.setPen(QtGui.QColor('#e54d42'))
        else:
            qp.setPen(QtCore.Qt.white)
        # finally, draw the text
        qp.drawText(self.rect(), 
            QtCore.Qt.AlignCenter | QtCore.Qt.TextShowMnemonic, self.text())

If you're using Designer, you'll need to promote the spinboxes:

  • select all radio buttons, right click on any of them and select Promote to... from the context menu;
  • ensure that the "Base class name" combobox is set to "QRadioButton";
  • in the "Promoted class name", write "CustomRadio" (the name of the subclass above);
  • in the "Header file" field write the name of the file in which you saved the subclass, without the extension (for example, if you are using main.py , write "main"); remember that the path is relative to that of the ui file (or py file, if you're using pyuic), so if the ui/py is in the main folder of your program, the subclass file is in the "subclasses" directory and is named "myradios.py", you'll have to write "subclasses.myradios" there;
  • click "Add" to create the new promoted class, and then "Promote" to actually promote the selected radios;
  • if you didn't select all radios before, now you can promote them by using the new "Custom Radio" item in the Promote to submenu of the context menu;

Save the ui file, generate the new python file if you use pyuic, and you're done.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM