这个例子相对综合一些,包括qt的布局,实现无边框效果,无边框也就是没有了窗口的title栏,没有title栏就不能拖动了,

所以我们进一步讲如何实现拖动。通过这边文章你可以掌握qt的布局,窗口定制,重写qt方法,QSS样式,事件信号

先上例子,后面在分析代码

#!/usr/bin/python3
# -*- coding: utf-8 -*- import sys
from PyQt5.QtWidgets import (QApplication, QWidget,QPushButton,
QLineEdit,QHBoxLayout, QVBoxLayout,QColorDialog,QInputDialog,QFileDialog)
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QCursor,QColor class Example(QWidget): def __init__(self):
super().__init__()
self.style = """
QPushButton{background-color:grey;color:white;}
#window{ background:pink; }
#test{ background-color:black;color:white; }
"""
self.setStyleSheet(self.style)
self.setWindowFlags(Qt.FramelessWindowHint)
self.initUI()
def initUI(self):
self.setGeometry(300, 300, 300, 220)
self.setWindowTitle('test')
self.setObjectName("window") btn1 = QPushButton("关闭",self)
btn1.clicked.connect(self.close)
btn1.setObjectName('test')
btn2 = QPushButton("最小化",self)
btn2.clicked.connect(self.showMinimized)
btn3 = QPushButton("最大化",self)
btn3.clicked.connect(self.showMaximized) btn11 = QPushButton("改变背景",self)
btn11.clicked.connect(self.showColor)
btn22 = QPushButton("选择文件",self)
btn22.clicked.connect(self.showFile)
btn33 = QPushButton("对话框",self)
btn33.clicked.connect(self.showDialog)
self.linet1 = QLineEdit("",self)
self.linet2 = QLineEdit("ssssssss",self) hbox1 = QHBoxLayout() #水平布局
hbox1.addWidget(btn1)
hbox1.addWidget(btn2)
hbox1.addWidget(btn3)
hbox2 = QHBoxLayout() #水平布局
hbox2.addWidget(btn11)
hbox2.addWidget(btn22)
hbox2.addWidget(btn33)
vbox = QVBoxLayout() #垂直布局
vbox.addLayout(hbox1)
vbox.addLayout(hbox2)
vbox.addWidget(self.linet1)
vbox.addWidget(self.linet2)
self.setLayout(vbox) self.show()
#重写三个方法使我们的Example窗口支持拖动,上面参数window就是拖动对象
def mousePressEvent(self, event):
if event.button()==Qt.LeftButton:
self.m_drag=True
self.m_DragPosition=event.globalPos()-self.pos()
event.accept()
self.setCursor(QCursor(Qt.OpenHandCursor))
def mouseMoveEvent(self, QMouseEvent):
if Qt.LeftButton and self.m_drag:
self.move(QMouseEvent.globalPos()-self.m_DragPosition)
QMouseEvent.accept()
def mouseReleaseEvent(self, QMouseEvent):
self.m_drag=False
self.setCursor(QCursor(Qt.ArrowCursor))
def showColor(self):
col = QColorDialog.getColor()
if col.isValid():
self.setStyleSheet(self.style+"#window{background:%s}" % col.name())
def showDialog(self):
text, ok = QInputDialog.getText(self, '对话框',
'请输入你的名字:') if ok:
self.linet1.setText(str(text))
def showFile(self):
fname = QFileDialog.getOpenFileName(self, 'Open file', '/home') if fname[0]:
f = open(fname[0], 'r') with f:
data = f.readline()
self.linet1.setText(data) if __name__ == '__main__':
app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())

运行效果:

上面导入的一大堆类我就不细说了,都是下面需要用到的,在我的上一篇文章中介绍了相关知识,这里只说一下,不要这样导入

from PyQt5.QtWidgets import *

这样子会把大量你没有用到的类都导入进来,占内存,所以尽量按需导入

self.style = """
QPushButton{background-color:grey;color:white;}
#window{ background:pink; }
#test{ background-color:black;color:white; }
"""
self.setStyleSheet(self.style)

这就是qt的css样式,和css基本是一样的写法,调用setStyleSheet方法把样式应用到当前self对象,也就是Example窗口

样式是可以继承的,和html/css是一个道理,我这个地方把样式绑定到顶层窗口,所以下面我添加的button也会去这个style里面去继承样式

和css一个道理,你在下面的button上可以再次调用setStyleSheet方法来覆盖继承的方法,

每一个窗口元素(比如按钮,输入框等等都算)都可以使用setObjectName(idname)来为一个对象取别名,然后我们就可以在样式里面单独指定样式,

比如我们有两个按钮,第一个按钮指定了别名test,看一下上面的写法是不是和css的id写法一样。就像个html中div加了一个id一样,然后在css文件里面用id来唯一标识样式

后面的按钮都没有指定别名,所以就默认继承 QPushButton{background-color:grey;color:white;}  样式,当然你还可以在button上调用setStyleSheet方法覆盖之前的样式

比如你在btn2下面加一行 btn2.setStyleSheet("QPushButton{background:green }")  就可以覆盖以前的样式了

怎么写样式就和css里面的一样,比如有这些: background,color,border,background-image,width,height等等

掌握了qss就可以写出各种花式界面了。

self.setWindowFlags(Qt.FramelessWindowHint)

这句话就是去掉窗口的顶部title栏了一级边框那些,对比一下去掉边框和没有去掉的区别

这个图片好像还看不出无边框的优越性,假设qq如果加上边框会是怎么的画面呢。。。

通常一些工具软件有无边框都无所谓,但是对于一些要求界面美观的软件来说带一个操作系统提供的外壳会显得略丑。。

加上上面那句代码后边框已经不见了,等等,以前移动都是鼠标按住顶部的title栏拖动的,现在title栏不见了还怎么拖动呢?

    def mousePressEvent(self, event):
if event.button()==Qt.LeftButton:
self.m_drag=True
self.m_DragPosition=event.globalPos()-self.pos()
event.accept()
self.setCursor(QCursor(Qt.OpenHandCursor))
def mouseMoveEvent(self, QMouseEvent):
if Qt.LeftButton and self.m_drag:
self.move(QMouseEvent.globalPos()-self.m_DragPosition)
QMouseEvent.accept()
def mouseReleaseEvent(self, QMouseEvent):
self.m_drag=False
self.setCursor(QCursor(Qt.ArrowCursor))

这三个方法是窗口对象自带的,默认情况下他好像什么都没干,所以我们可以大胆的重写这三个方法来实现拖动,

我相信看函数名大概也知道什么意思了吧,如果你写过js的拖动效果其实就不难理解了,

mousePressEvent流程:鼠标左键按下,设置拖动标识true,记录点击坐标,设置鼠标样式

mouseMoveEvent流程:判断当前数遍仍处于按下状态 ,调用move函数设置当前对标位置,

mouseReleaseEvent流程:释放拖动标示false

这下可以正常拖动了,等等,以前的最小化,最大化,关闭都在title栏上,现在也不见了,没有我们就自己实现呗

        btn1 = QPushButton("关闭",self)
btn1.clicked.connect(self.close)
btn1.setObjectName('test')
btn2 = QPushButton("最小化",self)
btn2.clicked.connect(self.showMinimized)
btn3 = QPushButton("最大化",self)
btn3.clicked.connect(self.showMaximized)

第一句:btn1 = QPushButton("关闭",self)  定义一个按钮对象,并指定他的容器是self,也就是放到Example窗口里面,

第二句是关键:当btn1被点击后会产生一个点击信号,然后把这个信号连接到self.close这个处理函数来处理这次事件

这个三个按钮连接的处理函数都是内建的函数,分别实现了关闭,最小最大化,

除了连接到qt提供的函数外,也可以连接到我们自己的函数,就像下面这样

    btn11 = QPushButton("改变背景",self)
btn11.clicked.connect(self.showColor)
btn22 = QPushButton("选择文件",self)
btn22.clicked.connect(self.showFile)
btn33 = QPushButton("对话框",self)
   btn33.clicked.connect(self.showDialog) def showColor(self):
col = QColorDialog.getColor()
if col.isValid():
self.setStyleSheet(self.style+"#window{background:%s}" % col.name())
def showDialog(self):
text, ok = QInputDialog.getText(self, '对话框',
'请输入你的名字:')
if ok:
self.linet1.setText(str(text))
def showFile(self):
fname = QFileDialog.getOpenFileName(self, 'Open file', '/home')
if fname[0]:
f = open(fname[0], 'r')
with f:
data = f.readline()
self.linet1.setText(data)

事件的作用就是用来发射信号,有些信号默认已经连接到处理函数,现在我们有这样的需求,就是我们要手动发出一个信号,换句话说就是我们自定义一个事件,

系统本身内部提供了很多事件,比如,click,mousemove,valuechange等等,除了这些我们仍然可以自定义事件,比如我把 鼠标向上移动接着向右移动 定义为一个事件,

这样我们可以做一些手势功能,这个要说起来又是一篇文章,就是提到这里吧,后面的文章在专门分析,初学者基本上用不到,

下面还是抛一个简单的模板列子

import sys
from PyQt5.QtCore import pyqtSignal, QObject
from PyQt5.QtWidgets import QMainWindow, QApplication class Communicate(QObject):
closeApp = pyqtSignal()
class Example(QMainWindow):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.c = Communicate()
self.c.closeApp.connect(self.close)
self.setGeometry(300, 300, 290, 150)
self.setWindowTitle('Emit signal')
self.show()
def mousePressEvent(self, event):
self.c.closeApp.emit()
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())

提示:发射信号的对象必须继承QObject类

说到这里突然发现漏了什么,对,就是布局

        hbox1 = QHBoxLayout()   #水平布局
hbox1.addWidget(btn1)
hbox1.addWidget(btn2)
hbox1.addWidget(btn3)
hbox2 = QHBoxLayout() #水平布局
hbox2.addWidget(btn11)
hbox2.addWidget(btn22)
hbox2.addWidget(btn33)
vbox = QVBoxLayout() #垂直布局
vbox.addLayout(hbox1)
vbox.addLayout(hbox2)
vbox.addWidget(self.linet1)
vbox.addWidget(self.linet2)
self.setLayout(vbox)

在qt中布局有三种,绝对定位,水平布局, 垂直布局, 网格布局

我上面使用的水平布局加垂直布局。通常一个软件会多种布局混合使用,布局是可以嵌套的。绝对定位是使用moveto函数来确定控件的位置,这种方式就把位置定死了,正常窗口下(非无边框),用户可以拖动边角进行放大窗口,或者点击最大化,

假设你的按钮的位置是(100,100),不管窗口变多大,按钮都是相对于窗口的左上角(0.0)位置,

绝对定位例子:

import sys
from PyQt5.QtWidgets import QWidget, QPushButton, QApplication app = QApplication(sys.argv)
wg = QWidget()
lbl1 = QPushButton('test', wg)
lbl1.move(15, 10)
wg.setGeometry(300, 300, 250, 150)
wg.setWindowTitle('Absolute')
wg.show()
sys.exit(app.exec_())

如果你的软件采用无边框,用户就无法改变窗口大小了,这种情况下采用绝对定位还是不错的。

如果你的软件允许用户改变大小,那么推荐使用流式布局,也就是水平布局和垂直布局以及网格布局都是流式布局

水平布局 就不需要例子了,最上面的综合例子就是采用水平布局加垂直布局

水平布局就是把所有的元素按照水平方向平铺,占满软件整个宽度,垂直布局一样的理解

说一下网格布局:

网格布局就是把你的软件花分成x*x的表格,比如5*5或者5x8等,然后你把控件插到相应位置就可以了,

网格布局例子:

import sys
from PyQt5.QtWidgets import (QWidget, QGridLayout,
QPushButton, QApplication) class Example(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
grid = QGridLayout()
self.setLayout(grid)
names = ['Cls', 'Bck', '', 'Close',
'', '', '', '/',
'', '', '', '*',
'', '', '', '-',
'', '.', '=', '+']
positions = [(i,j) for i in range(5) for j in range(4)]
for position, name in zip(positions, names):
if name == '':
continue
button = QPushButton(name)
grid.addWidget(button, *position) self.move(300, 150)
self.setWindowTitle('Calculator')
self.show() if __name__ == '__main__':
app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())

运行效果:

PyQt之布局&无边框&信号的更多相关文章

  1. 如何在pyqt中自定义无边框窗口

    前言 之前写过很多关于无边框窗口并给窗口添加特效的博客,按照时间线罗列如下: 如何在pyqt中实现窗口磨砂效果 如何在pyqt中实现win10亚克力效果 如何在pyqt中通过调用SetWindowCo ...

  2. 如何在pyqt中给无边框窗口添加DWM环绕阴影

    前言 在之前的博客<如何在pyqt中通过调用SetWindowCompositionAttribute实现Win10亚克力效果>中,我们实现了窗口的亚克力效果,同时也用SetWindowC ...

  3. 如何在pyqt中在实现无边框窗口的同时保留Windows窗口动画效果(一)

    无边框窗体的实现思路 在pyqt中只要 self.setWindowFlags(Qt.FramelessWindowHint) 就可以实现边框的去除,但是没了标题栏也意味着窗口大小无法改变.窗口无法拖 ...

  4. PyQt:无边框自定义标题栏及最大化最小化窗体大小调整

    环境 Python3.5.2 PyQt5 陈述 隐藏掉系统的控制栏,实现了自定义的标题控制栏,以及关闭/最大化/最小化的功能,自由调整窗体大小的功能(跟随一个大佬学的),代码内有详细注释 只要把Mai ...

  5. pyside pyqt QPushbuttion 无边框 stylesheet border:none

    pyside pyqt QPushbuttion 无边框 stylesheet border:none 在 stylesheet 中添加 border:none 即可 效果是字体到边缘之间的间隙为0, ...

  6. PYQT设计无边框窗体

    #UI.py,通过UI设计师制作后直接转换为UI.py脚本 # -*- coding: utf-8 -*-from PyQt4 import QtCore, QtGui try:    _fromUt ...

  7. Qt之界面(自定义标题栏、无边框、可移动、缩放)

    效果 自定义标题栏 titleBar.h #ifndef TITLEBAR_H #define TITLEBAR_H #include <QLabel> #include <QPus ...

  8. 无边框窗体、用户控件、Timer控件

    一.无边框窗体1 最大化.最小化以及关闭按钮制作实际上就是更换点击前.指向时.点击时的图片 (1)将图片放在该文件夹的Debug中,获取图片的路径Application.StartupPath + & ...

  9. pyqt4制作透明无边框窗体

    用PyQt做了一个无边框登陆窗口,效果如下: 下面是代码: # -*- coding: utf-8 -*- from PyQt4 import QtGui ,Qt ,QtCore image=QtGu ...

随机推荐

  1. 实例讲解表单验证插件Validation的应用

    jquery.Validation是一款优秀的jquery插件,它能对客户端表单进行验证,并且提供了许多可以定制的属性和方法,良好的扩展性.现在 结合实际情况,我把项目中经常要用到的验证整理成一个实例 ...

  2. Meet Github

    Source: http://www.liaoxuefeng.com/ Here only the local part. Install on windows download: https://g ...

  3. C# 发送邮件,QQ企业邮箱测试成功

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.N ...

  4. pip安装包报错:Microsoft Visual C++ 9.0 is required Unable to find vcvarsall.bat

    pip安装包报错:Microsoft Visual C++ 9.0 is required Unable to find vcvarsall.bat Windows7下pip安装包报错:Microso ...

  5. 【Android测试】【随笔】Android Studio环境搭建

    ◆版权声明:本文出自胖喵~的博客,转载必须注明出处. 转载请注明出处:http://www.cnblogs.com/by-dream/p/5482778.html 随着Android Studio的推 ...

  6. Java 基础【10】 I/O流概念分析整理

    转载地址:http://blog.csdn.net/yuebinghaoyuan/article/details/7388059 java.io 中的流,可以从不同的角度进行分类. 按照数据流的方向不 ...

  7. 更好的逐帧动画函数 — requestAnimationFrame 简介

    本文将会简单讲讲 requestAnimationFrame 函数的用法,与 setTimeout/setInterval 的区别和联系,以及当标签页隐藏时 requestAnimationFrame ...

  8. 如何在 ie6 中使用 "localStorage"

    好吧,我只是个标题党,ie6 下根本无法使用跟 h5 沾边的 localStorage.今天要向大家介绍的是 ie 特有的 userData 的存储方式,并且对它进行封装,使得不支持 localSto ...

  9. DOM与元素节点内联样式

    获取.设置及移除单个内联 CSS 属性 每个 HTML 元素都有个 style 属性,可以用来插入针对该元素的内联 CSS 属性. <div style='background-color:bl ...

  10. JSON简介以及用法汇总

    什么是JSON? JavaScript 对象表示法(JavaScript Object Notation). JSON是一种轻量级的数据交换格式,某个JSON格式的文件内部譬如可以长成这样: { &q ...