QTabWidget 在选项卡上设置掩码(不是选项卡内容)
QTabWidget set mask on tabs (not tab content)
我想使用 setMask
将 QTabWidget
上的选项卡(不是选项卡内容)的角变圆。我试过:
tabs = QTabWidget()
tempTabWidget = QRoundedTabWidget()
tabs.addTab(tempTabWidget,"New Tab")
#Tab widget that has rounded corners and
#inverted random corners at the bottom
class QRoundedTabWidget(QWidget):
def __init__(self,parent=None):
super(QWidget,self).__init__(parent)
self.radius = 3
self.tabHeight = 32
self.setMask(self.roundEdges(self.rect()))
def roundEdges(self,rectangle):
self.tabWidth = InterClassVariables.resizeTabWidth
region = QRegion()
region += rectangle.adjusted(self.radius,0,-self.radius,0)
region += rectangle.adjusted(0,self.radius,0,-self.radius)
#Top left corner piece
corner = QRect(rectangle.topLeft(),QSize(2 * self.radius,2 * self.radius))
region += QRegion(corner,QRegion.Ellipse)
#Top right corner piece
corner.moveTopRight(rectangle.topRight())
region += QRegion(corner,QRegion.Ellipse)
return region
但是,这会在选项卡的内容上放置一个掩码,而不是选项卡本身。我是否需要子类化 QTabWidget
对象来修改实际构建选项卡的 addTab
?我在哪里调用选项卡的子类小部件?
编辑:
这是我目前得到的 - 选项卡内容的两个顶角是圆形的:
这是我想要在选项卡上显示的内容:
实际的选项卡是一个 QTabBar。您可以使用样式表和 border-radius
属性 非常轻松地实现掩码。
class Template(QWidget):
def __init__(self):
super().__init__()
tabs = QTabWidget()
tabs.addTab(QWidget(), 'New Tab')
vbox = QVBoxLayout(self)
vbox.addWidget(tabs)
self.setStyleSheet('''
QTabBar::tab {
background-color: #555;
color: #fff;
padding: 6px;
border-top-left-radius: 6px;
border-top-right-radius: 6px;
}''')
文档中甚至有一个示例 here。
关于倒角,我不确定这是否可以通过样式表实现,但也许您可以重新实现绘画事件。 QPainterPath.quadTo()
将绘制二次贝塞尔曲线。
class Tab(QWidget):
def __init__(self, text, *args, **kwargs):
super().__init__(*args, **kwargs)
grid = QGridLayout(self)
grid.addWidget(QLabel(text), 0, 0, Qt.AlignCenter)
def paintEvent(self, event):
qp = QPainter(self)
qp.setRenderHint(QPainter.Antialiasing)
qp.setPen(Qt.NoPen)
qp.setBrush(QColor('#aaa'))
w, h = self.width(), self.height()
path = QPainterPath()
path.moveTo(0, h)
path.quadTo(w * 0.1, h, w * 0.1, h * 0.75)
path.lineTo(w * 0.1, h * 0.25)
path.quadTo(w * 0.1, 0, w * 0.2, 0)
path.lineTo(w * 0.8, 0)
path.quadTo(w * 0.9, 0, w * 0.9, h * 0.25)
path.lineTo(w * 0.9, h * 0.75)
path.quadTo(w * 0.9, h, w, h)
qp.drawPath(path)
看起来像这样:
编辑:不幸的是,现在要从中获得一个功能性选项卡小部件,我认为您必须稍微重新发明轮子。这是一个最小的例子:
class Tab(QAbstractButton):
def __init__(self, text, *args, **kwargs):
super().__init__(*args, **kwargs)
self.setCheckable(True)
grid = QGridLayout(self)
grid.addWidget(QLabel(text), 0, 0, Qt.AlignCenter)
def paintEvent(self, event):
qp = QPainter(self)
qp.setRenderHint(QPainter.Antialiasing)
qp.setPen(Qt.NoPen)
color = '#ccc' if self.isChecked() else '#aaa'
qp.setBrush(QColor(color))
w, h = self.width(), self.height()
path = QPainterPath()
path.moveTo(0, h)
path.quadTo(w * 0.1, h, w * 0.1, h * 0.75)
path.lineTo(w * 0.1, h * 0.25)
path.quadTo(w * 0.1, 0, w * 0.2, 0)
path.lineTo(w * 0.8, 0)
path.quadTo(w * 0.9, 0, w * 0.9, h * 0.25)
path.lineTo(w * 0.9, h * 0.75)
path.quadTo(w * 0.9, h, w, h)
qp.drawPath(path)
class TabWidget(QWidget):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.hbox = QHBoxLayout()
self.hbox.setSpacing(0)
self.qbg = QButtonGroup(self)
self.tabs = []
self.stacked_widget = QStackedWidget()
vbox = QVBoxLayout(self)
vbox.setSpacing(0)
vbox.addLayout(self.hbox)
vbox.addWidget(self.stacked_widget)
self.setStyleSheet('''
QStackedWidget {
background-color: #ccc;
border-radius: 4px;
}''')
def addTab(self, widget, text):
self.stacked_widget.addWidget(widget)
tab = Tab(text)
tab.clicked.connect(self.setCurrentTab)
self.tabs.append(tab)
self.hbox.addWidget(tab)
self.qbg.addButton(tab)
def setCurrentTab(self):
i = self.tabs.index(self.sender())
self.stacked_widget.setCurrentIndex(i)
class Template(QWidget):
def __init__(self):
super().__init__()
tabs = TabWidget()
tabs.addTab(Widget(), 'Tab 1')
tabs.addTab(Widget(), 'Tab 2')
vbox = QVBoxLayout(self)
vbox.addWidget(tabs)
我想使用 setMask
将 QTabWidget
上的选项卡(不是选项卡内容)的角变圆。我试过:
tabs = QTabWidget()
tempTabWidget = QRoundedTabWidget()
tabs.addTab(tempTabWidget,"New Tab")
#Tab widget that has rounded corners and
#inverted random corners at the bottom
class QRoundedTabWidget(QWidget):
def __init__(self,parent=None):
super(QWidget,self).__init__(parent)
self.radius = 3
self.tabHeight = 32
self.setMask(self.roundEdges(self.rect()))
def roundEdges(self,rectangle):
self.tabWidth = InterClassVariables.resizeTabWidth
region = QRegion()
region += rectangle.adjusted(self.radius,0,-self.radius,0)
region += rectangle.adjusted(0,self.radius,0,-self.radius)
#Top left corner piece
corner = QRect(rectangle.topLeft(),QSize(2 * self.radius,2 * self.radius))
region += QRegion(corner,QRegion.Ellipse)
#Top right corner piece
corner.moveTopRight(rectangle.topRight())
region += QRegion(corner,QRegion.Ellipse)
return region
但是,这会在选项卡的内容上放置一个掩码,而不是选项卡本身。我是否需要子类化 QTabWidget
对象来修改实际构建选项卡的 addTab
?我在哪里调用选项卡的子类小部件?
编辑:
这是我目前得到的 - 选项卡内容的两个顶角是圆形的:
这是我想要在选项卡上显示的内容:
实际的选项卡是一个 QTabBar。您可以使用样式表和 border-radius
属性 非常轻松地实现掩码。
class Template(QWidget):
def __init__(self):
super().__init__()
tabs = QTabWidget()
tabs.addTab(QWidget(), 'New Tab')
vbox = QVBoxLayout(self)
vbox.addWidget(tabs)
self.setStyleSheet('''
QTabBar::tab {
background-color: #555;
color: #fff;
padding: 6px;
border-top-left-radius: 6px;
border-top-right-radius: 6px;
}''')
文档中甚至有一个示例 here。
关于倒角,我不确定这是否可以通过样式表实现,但也许您可以重新实现绘画事件。 QPainterPath.quadTo()
将绘制二次贝塞尔曲线。
class Tab(QWidget):
def __init__(self, text, *args, **kwargs):
super().__init__(*args, **kwargs)
grid = QGridLayout(self)
grid.addWidget(QLabel(text), 0, 0, Qt.AlignCenter)
def paintEvent(self, event):
qp = QPainter(self)
qp.setRenderHint(QPainter.Antialiasing)
qp.setPen(Qt.NoPen)
qp.setBrush(QColor('#aaa'))
w, h = self.width(), self.height()
path = QPainterPath()
path.moveTo(0, h)
path.quadTo(w * 0.1, h, w * 0.1, h * 0.75)
path.lineTo(w * 0.1, h * 0.25)
path.quadTo(w * 0.1, 0, w * 0.2, 0)
path.lineTo(w * 0.8, 0)
path.quadTo(w * 0.9, 0, w * 0.9, h * 0.25)
path.lineTo(w * 0.9, h * 0.75)
path.quadTo(w * 0.9, h, w, h)
qp.drawPath(path)
看起来像这样:
编辑:不幸的是,现在要从中获得一个功能性选项卡小部件,我认为您必须稍微重新发明轮子。这是一个最小的例子:
class Tab(QAbstractButton):
def __init__(self, text, *args, **kwargs):
super().__init__(*args, **kwargs)
self.setCheckable(True)
grid = QGridLayout(self)
grid.addWidget(QLabel(text), 0, 0, Qt.AlignCenter)
def paintEvent(self, event):
qp = QPainter(self)
qp.setRenderHint(QPainter.Antialiasing)
qp.setPen(Qt.NoPen)
color = '#ccc' if self.isChecked() else '#aaa'
qp.setBrush(QColor(color))
w, h = self.width(), self.height()
path = QPainterPath()
path.moveTo(0, h)
path.quadTo(w * 0.1, h, w * 0.1, h * 0.75)
path.lineTo(w * 0.1, h * 0.25)
path.quadTo(w * 0.1, 0, w * 0.2, 0)
path.lineTo(w * 0.8, 0)
path.quadTo(w * 0.9, 0, w * 0.9, h * 0.25)
path.lineTo(w * 0.9, h * 0.75)
path.quadTo(w * 0.9, h, w, h)
qp.drawPath(path)
class TabWidget(QWidget):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.hbox = QHBoxLayout()
self.hbox.setSpacing(0)
self.qbg = QButtonGroup(self)
self.tabs = []
self.stacked_widget = QStackedWidget()
vbox = QVBoxLayout(self)
vbox.setSpacing(0)
vbox.addLayout(self.hbox)
vbox.addWidget(self.stacked_widget)
self.setStyleSheet('''
QStackedWidget {
background-color: #ccc;
border-radius: 4px;
}''')
def addTab(self, widget, text):
self.stacked_widget.addWidget(widget)
tab = Tab(text)
tab.clicked.connect(self.setCurrentTab)
self.tabs.append(tab)
self.hbox.addWidget(tab)
self.qbg.addButton(tab)
def setCurrentTab(self):
i = self.tabs.index(self.sender())
self.stacked_widget.setCurrentIndex(i)
class Template(QWidget):
def __init__(self):
super().__init__()
tabs = TabWidget()
tabs.addTab(Widget(), 'Tab 1')
tabs.addTab(Widget(), 'Tab 2')
vbox = QVBoxLayout(self)
vbox.addWidget(tabs)