技术分享pyqt5PyQt5技术分享_制作一个美观的Dock栏
MGodmonkey
一周一小步,一年一大步!欧!耶!
这周我完成了软件项目的一个重要的部件–dock栏,闲话少说,先上成品!!!
1.创建透明窗口
要实现这样一个小窗口当然需要先创建一个QWidget类,并对QWidget的背景,窗口大小,边框等等做一些小设置,这里的背景用QPinter动态描绘上边框和背景色(具体的paintEvent代码的也是从某大师那里抄的,具体哪个,我给忘了,,,)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
| class Dock_Win(QWidget): def __init__(self, parent=None): super(Dock_Win, self).__init__(parent) self.bg_color = QColor(170, 248, 248, 230) self.fill_color = QColor(0,250,255,50) self.initUI() def initUI(self): self.setAttribute(Qt.WA_TranslucentBackground) self.setWindowFlags(Qt.FramelessWindowHint | Qt.Dialog) self.resize(462, 110)
def paintEvent(self, event): painter_path = QPainterPath() painter_path.setFillRule(Qt.WindingFill)
painter = QPainter(self) painter.setRenderHint(QPainter.Antialiasing) painter.fillPath(painter_path, QBrush(Qt.white)) for i in range(10): i_path = QPainterPath() i_path.setFillRule(Qt.WindingFill) ref = QRectF(10 - i, 10 - i, self.width() - (10 - i) * 2, self.height() - (10 - i) * 2) i_path.addRoundedRect(ref, 20, 20) self.fill_color.setAlpha(int(150 - i ** 0.5 * 50)) painter.setPen(self.fill_color) painter.drawPath(i_path)
self.painter_rect = QPainter(self) self.painter_rect.setRenderHint(QPainter.Antialiasing) self.painter_rect.setBrush(self.bg_color) self.painter_rect.setPen(Qt.transparent)
self._rect = self.rect() self._rect.setLeft(15) self._rect.setTop(15) self._rect.setWidth(self._rect.width() - 15) self._rect.setHeight(self._rect.height() - 15) self.painter_rect.begin(self) self.painter_rect.drawRoundedRect(self._rect, 15, 15) self.painter_rect.end()
|
这样我们就得到了一个时尚而不失优雅的背景窗口
2.为窗口添加移动事件
无边框的窗口在美观的同时,也失去了边框所带来的移动便利,没有了边框的窗口,你左击并移动鼠标,跟在一个空白窗口上乱画没啥区别,所以要对主窗口的mouseMoveEvent()鼠标移动事件进行重写
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| def mousePressEvent(self, event): if event.button() == Qt.LeftButton: self.is_move = True self.move_xy = event.globalPos() - self.pos() self.setCursor(QCursor(Qt.OpenHandCursor))
def mouseMoveEvent(self, event): if self.is_move: self.move(event.globalPos() - self.move_xy)
def mouseReleaseEvent(self, event): self.is_move = False self.setCursor(QCursor(Qt.ArrowCursor))
|
这样窗口就被你牢牢的把握在手心了
3.添加组件
光有窗口肯定是不够的,肯定要有选项啊,这里的选项我尝试了很多种,有QPushButton,有QListWidget,但由于知识储备量不够,都一一失败了(尬``),最后还不如QLabel来的痛快,这里直接定制一个QLabel
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
| class QLabel_Item(QLabel): cliecked = pyqtSignal() def __init__(self,index,QIcon_no,QIcon_on,text=None,parent=None): super(QLabel_Item, self).__init__(parent) self.icon_no = QIcon_no self.icon_on = QIcon_on self.is_clieck = True if index != 1: self.is_open = False self.setScaledContents(True) self.setPixmap(QPixmap(QIcon_no)) else: self.is_open = True self.setScaledContents(True) self.setPixmap(QPixmap(QIcon_on)) if index != 3: if index > 3: _plus = 26 else: _plus = 0 self.setGeometry(36*index+46*(index-1)+_plus, 26, 46, 46) self.bottom_text = QLabel(text, parent) self.bottom_text.setFont(QFont('华文新魏', 10)) self.bottom_text.setAlignment(Qt.AlignCenter) self.bottom_text.setGeometry(36*index+46*(index-1)+_plus, 74, 46, 16) else: self.setScaledContents(True) self.setPixmap(QPixmap(QIcon_no)) self.setGeometry(200, 20, 72, 72) self.setObjectName('play') self.setToolTip('点击播放')
def set_no(self): self.setPixmap(QPixmap(self.icon_no)) self.bottom_text.setStyleSheet('text-decoration:normal;')
def set_on(self): self.setPixmap(QPixmap(self.icon_on)) self.bottom_text.setStyleSheet('text-decoration:underline;')
def mousePressEvent(self, event): if event.button() == Qt.LeftButton: self.is_clieck = True self.move_xy = event.globalPos() - self.pos() self.parent_rect = self.parent().pos()
def mouseMoveEvent(self, event): self.is_clieck = False self.parent().move(self.parent_rect + event.globalPos() - self.move_xy - self.pos()) self.setCursor(QCursor(Qt.OpenHandCursor)) self.moved = True
def mouseReleaseEvent(self, event): if event.button() == Qt.LeftButton: self.setCursor(QCursor(Qt.ArrowCursor)) if self.is_clieck and not self.is_open: self.is_open = True self.cliecked.emit() elif self.is_clieck: self.is_open = False self.cliecked.emit()
|
- 因为QLabel本身是不支持点击事件的,所以要创建一个clieck信号
- 为了让鼠标移动到图标上和点击图标时有更好的反馈效果,QLabel_Item()创建需要传入打开时的图标,关闭时的图标,底部文本和父窗口(使用绝对布局时需要)
- 另图标的鼠标事件也是很重要的啊,鼠标的点击,移动,出入都需要图标进行一个很好的反馈效果
- 因为中间的播放按钮不是用来进行主界面口切换的,所以要进行特殊关照(你懂的<-.<-)
注:因为QLabel和QLabel是同一类的,所以创建底部文字时,不能将图标的QLabel设为父类,QLabel只能作为图片,文本的容器
4.窗口的右击菜单
窗口的右击菜单可以用来对dock栏进行一些设置,这就需要对contextMenuEvent()进行重写
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
| def contextMenuEvent(self, event): right_menu = QMenu(self) set_bg_color = QAction('背景色') right_menu.addAction(set_bg_color)
set_bg_color.triggered.connect(lambda: self.changeBgColor(''))
set_gh_color = QAction('光圈色') right_menu.addAction(set_gh_color) set_gh_color.triggered.connect(lambda: self.changeGhColor(''))
exit_menu = QAction('退 出',right_menu) exit_menu.triggered.connect(right_menu.close) auto_hide = QAction('自动隐藏') right_menu.addAction(auto_hide) right_menu.addSeparator() right_menu.addAction(exit_menu) if not self.childAt(event.globalPos()-self.pos()): right_menu.exec_(event.globalPos())
|
可以看到我这里原本预定了很多好看的颜色,尝试过直接对self.bg_color()进行改变,刷新界面,但不知道为什么最后只有QColorDialog成功了,无奈,只能摸摸自己所剩无几的头发,叹了叹气,放弃了,如果有大神愿为后辈指点一二,吾辈定当无比感谢!(拜托了,yyy)
因为项目的主窗口还在画饼中,所以dock栏的些许功能尚未完善
最后源码献上:代码入口
题外:
原本项目的登录界面已经做好的,而登录账号用来桂电的VPN账号,方便后续直接访问校内资源,写了篇关于调用桂电VPN接口的博客,但奈何官方对这方面的博客把控太严,无奈只能设为私密了(这里没有抱怨,而是称赞审查大大的一丝不苟,兢兢业业···(此处省略一万字))
这里的UI还没美化完全,后期会定制qss文件专门美化的,而项目的进程不能因为部分而拖太久了