写在前面
写了一个登录界面的demo,类似QQ的,写的自己喜欢的样式,贴一下代码,先上效果,如下
陈述
PyQt5+Python3.5.2
login.py是里登录的主界面loginWnd类,Header.py里是标题栏和整个窗口的类,我在login.py里面创建了application对象。(其实也没有必要分成两个文件来写,直接按照我这一篇的处理就ok的 https://www.cnblogs.com/jyroy/p/9461317.html,本人话多)
主要是效果实现为主,没有写登录的槽函数啥的,代码中写了解释
效果
代码
1 #login.py 2 3 #!/usr/bin/env python 4 # -*- coding:utf-8 -*- 5 # Author: jyroy 6 import sys 7 8 from PyQt5.QtCore import QSize 9 from PyQt5.QtWidgets import QApplication 10 from PyQt5.QtCore import Qt 11 from PyQt5.QtWidgets import QComboBox 12 from PyQt5.QtWidgets import QGridLayout 13 from PyQt5.QtWidgets import QLineEdit 14 from PyQt5.QtWidgets import QLabel 15 from PyQt5.QtGui import QIcon 16 from PyQt5.QtWidgets import QWidget, QVBoxLayout, QPushButton, QTextEdit 17 from Header import TitleBar,FramelessWindow 18 from qtpy import QtGui 19 20 StyleSheet = """ 21 /*最小化最大化关闭按钮通用默认背景*/ 22 #buttonMinimum,#buttonMaximum,#buttonClose { 23 border: none; 24 } 25 /*悬停*/ 26 #buttonMinimum:hover,#buttonMaximum:hover { 27 28 color: white; 29 } 30 #buttonClose:hover { 31 color: white; 32 } 33 /*鼠标按下不放*/ 34 #buttonMinimum:pressed,#buttonMaximum:pressed { 35 36 } 37 #buttonClose:pressed { 38 color: white; 39 40 } 41 """ #标题栏Button的样式 42 43 StyleSheet_2 = """ 44 QComboBox{ 45 height: 20px; 46 border-radius: 4px; 47 border: 1px solid rgb(111, 156, 207); 48 background: white; 49 } 50 QComboBox:enabled{ 51 color: grey; 52 } 53 QComboBox:!enabled { 54 color: rgb(80, 80, 80); 55 } 56 QComboBox:enabled:hover, QComboBox:enabled:focus { 57 color: rgb(51, 51, 51); 58 } 59 QComboBox::drop-down { 60 background: transparent; 61 } 62 QComboBox::drop-down:hover { 63 background: lightgrey; 64 } 65 66 QComboBox QAbstractItemView { 67 border: 1px solid rgb(111, 156, 207); 68 background: white; 69 outline: none; 70 } 71 72 QLineEdit { 73 border-radius: 4px; 74 height: 20px; 75 border: 1px solid rgb(111, 156, 207); 76 background: white; 77 } 78 QLineEdit:enabled { 79 color: rgb(84, 84, 84); 80 } 81 QLineEdit:enabled:hover, QLineEdit:enabled:focus { 82 color: rgb(51, 51, 51); 83 } 84 QLineEdit:!enabled { 85 color: rgb(80, 80, 80); 86 } 87 88 89 """ #QComobox和QLineEdite的样式 90 91 StyleSheet_btn = """ 92 QPushButton{ 93 height:30px; 94 background-color: transparent; 95 color: grey; 96 border: 2px solid #555555; 97 border-radius: 6px; 98 99 } 100 QPushButton:hover { 101 background-color: white; 102 border-radius: 6px; 103 104 } 105 """ #登录Button的样式 106 107 class loginWnd(QWidget): 108 '''登录窗口''' 109 def __init__(self, *args, **kwargs): 110 super(loginWnd, self).__init__() 111 self._layout = QVBoxLayout(spacing=0) 112 self._layout.setContentsMargins(0, 0, 0, 0) 113 self.setAutoFillBackground(True) 114 self.setWindowOpacity(0.1) 115 116 self.setLayout(self._layout) 117 118 self._setup_ui() 119 120 def _setup_ui(self): 121 122 self.main_layout = QGridLayout() 123 124 self.main_layout.setAlignment(Qt.AlignCenter) 125 126 name_label = QLabel('用户名') 127 name_label.setStyleSheet("color:grey;") 128 passwd_label = QLabel('密码') 129 passwd_label.setStyleSheet("color:grey;") 130 131 name_box = QComboBox() 132 name_box.setEditable(True) 133 passwd_box = QLineEdit() 134 passwd_box.setEchoMode(QLineEdit.Password) 135 name_box.setStyleSheet(StyleSheet_2) 136 passwd_box.setStyleSheet(StyleSheet_2) 137 138 label = QLabel() 139 140 login_btn = QPushButton("登录") 141 login_btn.setStyleSheet(StyleSheet_btn) 142 143 self.main_layout.addWidget(name_label,0,0,1,1) 144 self.main_layout.addWidget(passwd_label,1,0,1,1) 145 self.main_layout.addWidget(name_box,0,1,1,2) 146 self.main_layout.addWidget(passwd_box,1,1,1, 2) 147 self.main_layout.addWidget(label,3,0,1,3) 148 self.main_layout.addWidget(login_btn,4,0,1,3) 149 150 self._layout.addLayout(self.main_layout) 151 152 def main(): 153 ''':return:''' 154 155 app = QApplication(sys.argv) 156 157 mainWnd = FramelessWindow() 158 mainWnd.setWindowTitle('欢迎窗口login') 159 mainWnd.setWindowIcon(QIcon('Qt.ico')) 160 mainWnd.setFixedSize(QSize(500,400)) #因为这里固定了大小,所以窗口的大小没有办法任意调整,想要使resizeWidget函数生效的话要把这里去掉,自己调节布局和窗口大小 161 mainWnd.setWidget(loginWnd(mainWnd)) # 把自己的窗口添加进来 162 mainWnd.show() 163 164 app.exec() 165 166 if __name__ == '__main__': 167 main()
1 #Header.py 2 3 #!/usr/bin/env python 4 # -*- coding:utf-8 -*- 5 # Author: jyroy 6 7 from PyQt5.QtCore import Qt, pyqtSignal, QPoint 8 from PyQt5.QtGui import QFont, QEnterEvent, QPainter, QColor, QPen 9 from PyQt5.QtWidgets import QHBoxLayout, QLabel,QSpacerItem, QSizePolicy 10 from PyQt5.QtWidgets import QWidget, QVBoxLayout, QPushButton, QTextEdit 11 from qtpy import QtGui 12 13 StyleSheet = """ 14 /*最小化最大化关闭按钮通用默认背景*/ 15 #buttonMinimum,#buttonMaximum,#buttonClose { 16 border: none; 17 } 18 #buttonClose,#buttonMaximum,#buttonMinimum{ 19 color:grey; 20 } 21 /*悬停*/ 22 #buttonMinimum:hover,#buttonMaximum:hover { 23 color: white; 24 } 25 #buttonClose:hover { 26 color: white; 27 } 28 /*鼠标按下不放*/ 29 #buttonMinimum:pressed,#buttonMaximum:pressed { 30 color:grey; 31 } 32 #buttonClose:pressed { 33 color: white; 34 35 } 36 """ 37 class TitleBar(QWidget): 38 39 # 窗口最小化信号 40 windowMinimumed = pyqtSignal() 41 # 窗口最大化信号 42 windowMaximumed = pyqtSignal() 43 # 窗口还原信号 44 windowNormaled = pyqtSignal() 45 # 窗口关闭信号 46 windowClosed = pyqtSignal() 47 # 窗口移动 48 windowMoved = pyqtSignal(QPoint) 49 50 def __init__(self, *args, **kwargs): 51 super(TitleBar, self).__init__(*args, **kwargs) 52 self.setStyleSheet(StyleSheet) 53 self.mPos = None 54 self.iconSize = 20 # 图标的默认大小 55 # 布局 56 layout = QHBoxLayout(self, spacing=0) 57 layout.setContentsMargins(0, 0, 0, 0) 58 # 窗口图标 59 self.iconLabel = QLabel(self) 60 # self.iconLabel.setScaledContents(True) 61 layout.addWidget(self.iconLabel) 62 # 窗口标题 63 self.titleLabel = QLabel(self) 64 self.titleLabel.setStyleSheet("color:grey") 65 self.titleLabel.setMargin(2) 66 layout.addWidget(self.titleLabel) 67 # 中间伸缩条 68 layout.addSpacerItem(QSpacerItem( 69 40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum)) 70 # 利用Webdings字体来显示图标 71 font = self.font() or QFont() 72 font.setFamily('Webdings') 73 # 最小化按钮 74 self.buttonMinimum = QPushButton( 75 '0', self, clicked=self.windowMinimumed.emit, font=font, objectName='buttonMinimum') 76 layout.addWidget(self.buttonMinimum) 77 # 最大化/还原按钮 78 self.buttonMaximum = QPushButton( 79 '1', self, clicked=self.showMaximized, font=font, objectName='buttonMaximum') 80 layout.addWidget(self.buttonMaximum) 81 # 关闭按钮 82 self.buttonClose = QPushButton( 83 'r', self, clicked=self.windowClosed.emit, font=font, objectName='buttonClose') 84 layout.addWidget(self.buttonClose) 85 # 初始高度 86 self.setHeight() 87 88 def showMaximized(self): 89 if self.buttonMaximum.text() == '1': 90 # 最大化 91 self.buttonMaximum.setText('2') 92 self.windowMaximumed.emit() 93 else: # 还原 94 self.buttonMaximum.setText('1') 95 self.windowNormaled.emit() 96 97 def setHeight(self, height=38): 98 """设置标题栏高度""" 99 self.setMinimumHeight(height) 100 self.setMaximumHeight(height) 101 # 设置右边按钮的大小 102 self.buttonMinimum.setMinimumSize(height, height) 103 self.buttonMinimum.setMaximumSize(height, height) 104 self.buttonMaximum.setMinimumSize(height, height) 105 self.buttonMaximum.setMaximumSize(height, height) 106 self.buttonClose.setMinimumSize(height, height) 107 self.buttonClose.setMaximumSize(height, height) 108 109 def setTitle(self, title): 110 """设置标题""" 111 self.titleLabel.setText(title) 112 113 def setIcon(self, icon): 114 """设置图标""" 115 self.iconLabel.setPixmap(icon.pixmap(self.iconSize, self.iconSize)) 116 117 def setIconSize(self, size): 118 """设置图标大小""" 119 self.iconSize = size 120 121 def enterEvent(self, event): 122 self.setCursor(Qt.ArrowCursor) 123 super(TitleBar, self).enterEvent(event) 124 125 def mouseDoubleClickEvent(self, event): 126 super(TitleBar, self).mouseDoubleClickEvent(event) 127 self.showMaximized() 128 129 def mousePressEvent(self, event): 130 """鼠标点击事件""" 131 if event.button() == Qt.LeftButton: 132 self.mPos = event.pos() 133 event.accept() 134 135 def mouseReleaseEvent(self, event): 136 '''鼠标弹起事件''' 137 self.mPos = None 138 event.accept() 139 140 def mouseMoveEvent(self, event): 141 if event.buttons() == Qt.LeftButton and self.mPos: 142 self.windowMoved.emit(self.mapToGlobal(event.pos() - self.mPos)) 143 event.accept() 144 145 # 枚举左上右下以及四个定点 146 Left, Top, Right, Bottom, LeftTop, RightTop, LeftBottom, RightBottom = range(8) 147 148 class FramelessWindow(QWidget): 149 150 # 四周边距 151 Margins = 5 152 153 def __init__(self, *args, **kwargs): 154 super(FramelessWindow, self).__init__(*args, **kwargs) 155 palette1 = QtGui.QPalette() 156 palette1.setBrush(self.backgroundRole(), QtGui.QBrush( 157 QtGui.QPixmap('D:\python\code\qilucontest\qt\WholeDemo/resource/sky.jpg'))) # 设置背景图片 158 self.setPalette(palette1) 159 self.setAutoFillBackground(True) 160 self.setGeometry(300, 300, 250, 150) 161 self._pressed = False 162 self.Direction = None 163 # 无边框 164 self.setWindowFlags(Qt.FramelessWindowHint) # 隐藏边框 165 # 鼠标跟踪 166 self.setMouseTracking(True) 167 # 布局 168 layout = QVBoxLayout(self, spacing=0) 169 layout.setContentsMargins(0,0,0,0) 170 # 标题栏 171 self.titleBar = TitleBar(self) 172 layout.addWidget(self.titleBar) 173 # 信号槽 174 self.titleBar.windowMinimumed.connect(self.showMinimized) 175 self.titleBar.windowMaximumed.connect(self.showMaximized) 176 self.titleBar.windowNormaled.connect(self.showNormal) 177 self.titleBar.windowClosed.connect(self.close) 178 self.titleBar.windowMoved.connect(self.move) 179 self.windowTitleChanged.connect(self.titleBar.setTitle) 180 self.windowIconChanged.connect(self.titleBar.setIcon) 181 182 def setTitleBarHeight(self, height=38): 183 """设置标题栏高度""" 184 self.titleBar.setHeight(height) 185 186 def setIconSize(self, size): 187 """设置图标的大小""" 188 self.titleBar.setIconSize(size) 189 190 def setWidget(self, widget): 191 """设置自己的控件""" 192 if hasattr(self, '_widget'): 193 return 194 self._widget = widget 195 # 设置默认背景颜色,否则由于受到父窗口的影响导致透明 196 self._widget.setAutoFillBackground(True) 197 self._widget.installEventFilter(self) 198 self.layout().addWidget(self._widget) 199 200 def move(self, pos): 201 if self.windowState() == Qt.WindowMaximized or self.windowState() == Qt.WindowFullScreen: 202 # 最大化或者全屏则不允许移动 203 return 204 super(FramelessWindow, self).move(pos) 205 206 def showMaximized(self): 207 """最大化,要去除上下左右边界,如果不去除则边框地方会有空隙""" 208 super(FramelessWindow, self).showMaximized() 209 self.layout().setContentsMargins(0, 0, 0, 0) 210 211 def showNormal(self): 212 """还原,要保留上下左右边界,否则没有边框无法调整""" 213 super(FramelessWindow, self).showNormal() 214 self.layout().setContentsMargins(0, 0, 0, 0) 215 216 def eventFilter(self, obj, event): 217 """事件过滤器,用于解决鼠标进入其它控件后还原为标准鼠标样式""" 218 if isinstance(event, QEnterEvent): 219 self.setCursor(Qt.ArrowCursor) 220 return super(FramelessWindow, self).eventFilter(obj, event) 221 222 def paintEvent(self, event): 223 """由于是全透明背景窗口,重绘事件中绘制透明度为1的难以发现的边框,用于调整窗口大小""" 224 super(FramelessWindow, self).paintEvent(event) 225 painter = QPainter(self) 226 painter.setPen(QPen(QColor(255, 255, 255, 1), 2 * self.Margins)) 227 painter.drawRect(self.rect()) 228 229 def mousePressEvent(self, event): 230 """鼠标点击事件""" 231 super(FramelessWindow, self).mousePressEvent(event) 232 if event.button() == Qt.LeftButton: 233 self._mpos = event.pos() 234 self._pressed = True 235 236 def mouseReleaseEvent(self, event): 237 '''鼠标弹起事件''' 238 super(FramelessWindow, self).mouseReleaseEvent(event) 239 self._pressed = False 240 self.Direction = None 241 242 def mouseMoveEvent(self, event): 243 """鼠标移动事件""" 244 super(FramelessWindow, self).mouseMoveEvent(event) 245 pos = event.pos() 246 xPos, yPos = pos.x(), pos.y() 247 wm, hm = self.width() - self.Margins, self.height() - self.Margins 248 if self.isMaximized() or self.isFullScreen(): 249 self.Direction = None 250 self.setCursor(Qt.ArrowCursor) 251 return 252 if event.buttons() == Qt.LeftButton and self._pressed: 253 self._resizeWidget(pos) 254 return 255 if xPos <= self.Margins and yPos <= self.Margins: 256 # 左上角 257 self.Direction = LeftTop 258 self.setCursor(Qt.SizeFDiagCursor) 259 elif wm <= xPos <= self.width() and hm <= yPos <= self.height(): 260 # 右下角 261 self.Direction = RightBottom 262 self.setCursor(Qt.SizeFDiagCursor) 263 elif wm <= xPos and yPos <= self.Margins: 264 # 右上角 265 self.Direction = RightTop 266 self.setCursor(Qt.SizeBDiagCursor) 267 elif xPos <= self.Margins and hm <= yPos: 268 # 左下角 269 self.Direction = LeftBottom 270 self.setCursor(Qt.SizeBDiagCursor) 271 elif 0 <= xPos <= self.Margins and self.Margins <= yPos <= hm: 272 # 左边 273 self.Direction = Left 274 self.setCursor(Qt.SizeHorCursor) 275 elif wm <= xPos <= self.width() and self.Margins <= yPos <= hm: 276 # 右边 277 self.Direction = Right 278 self.setCursor(Qt.SizeHorCursor) 279 elif self.Margins <= xPos <= wm and 0 <= yPos <= self.Margins: 280 # 上面 281 self.Direction = Top 282 self.setCursor(Qt.SizeVerCursor) 283 elif self.Margins <= xPos <= wm and hm <= yPos <= self.height(): 284 # 下面 285 self.Direction = Bottom 286 self.setCursor(Qt.SizeVerCursor) 287 288 def _resizeWidget(self, pos): 289 """调整窗口大小""" 290 if self.Direction == None: 291 return 292 mpos = pos - self._mpos 293 xPos, yPos = mpos.x(), mpos.y() 294 geometry = self.geometry() 295 x, y, w, h = geometry.x(), geometry.y(), geometry.width(), geometry.height() 296 if self.Direction == LeftTop: # 左上角 297 if w - xPos > self.minimumWidth(): 298 x += xPos 299 w -= xPos 300 if h - yPos > self.minimumHeight(): 301 y += yPos 302 h -= yPos 303 elif self.Direction == RightBottom: # 右下角 304 if w + xPos > self.minimumWidth(): 305 w += xPos 306 self._mpos = pos 307 if h + yPos > self.minimumHeight(): 308 h += yPos 309 self._mpos = pos 310 elif self.Direction == RightTop: # 右上角 311 if h - yPos > self.minimumHeight(): 312 y += yPos 313 h -= yPos 314 if w + xPos > self.minimumWidth(): 315 w += xPos 316 self._mpos.setX(pos.x()) 317 elif self.Direction == LeftBottom: # 左下角 318 if w - xPos > self.minimumWidth(): 319 x += xPos 320 w -= xPos 321 if h + yPos > self.minimumHeight(): 322 h += yPos 323 self._mpos.setY(pos.y()) 324 elif self.Direction == Left: # 左边 325 if w - xPos > self.minimumWidth(): 326 x += xPos 327 w -= xPos 328 else: 329 return 330 elif self.Direction == Right: # 右边 331 if w + xPos > self.minimumWidth(): 332 w += xPos 333 self._mpos = pos 334 else: 335 return 336 elif self.Direction == Top: # 上面 337 if h - yPos > self.minimumHeight(): 338 y += yPos 339 h -= yPos 340 else: 341 return 342 elif self.Direction == Bottom: # 下面 343 if h + yPos > self.minimumHeight(): 344 h += yPos 345 self._mpos = pos 346 else: 347 return 348 self.setGeometry(x, y, w, h)