寫了一個登陸界面的demo,相似QQ的,寫的本身喜歡的樣式,貼一下代碼,先上效果,以下html
PyQt5+Python3.5.2python
login.py是裏登陸的主界面loginWnd類,Header.py裏是標題欄和整個窗口的類,我在login.py裏面建立了application對象。(其實也沒有必要分紅兩個文件來寫,直接按照我這一篇的處理就ok的 https://www.cnblogs.com/jyroy/p/9461317.html,本人話多)app
主要是效果實現爲主,沒有寫登陸的槽函數啥的,代碼中寫了解釋less
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)