How to set width QVboxLayout - python

import sys
from PySide2.QtCore import *
from PySide2.QtGui import *
from PySide2.QtWidgets import QApplication,QDialog,QPushButton,QVBoxLayout,QWidget
class Main(QDialog):
def __init__(self):
super(Main, self).__init__()
self.ui()
# Group Of Drage Event
def mousePressEvent(self,event):
self.offset = event.pos()
def mouseMoveEvent(self, e):
x = e.globalX()
y = e.globalY()
x_w = self.offset.x()
y_w = self.offset.y()
self.move(x - x_w, y - y_w)
def ui(self):
# TitleBar
self.setWindowFlags(Qt.FramelessWindowHint)
# Window Size
self.setGeometry(600,300,400,500)
# Window Background Color
self.BackGroundColor = QPalette()
self.BackGroundColor.setColor(QPalette.Background, QColor(255,255,255))
self.setPalette(self.BackGroundColor)
# NavBar Button
self.btn = QPushButton('Test',self)
self.btn1 = QPushButton("Test1",self)
# NavBar Layout
self.layout = QVBoxLayout(self)
self.layout.addWidget(self.btn)
self.layout.addWidget(self.btn1)
self.layout.set
self.setLayout(self.layout)
# Close img
self.closeBtn = QPushButton(self)
self.closeBtn.setGeometry(368,0,32,32)
self.closeBtn.setFlat(True)
self.closeBtn.setStyleSheet('QPushButton{background-color: rgba(0,0,0,0.0)}')
self.closeBtn.setIcon(QIcon('img/close.png'))
self.closeBtn.setIconSize(QSize(10,10))
self.closeBtn.clicked.connect(QCoreApplication.instance().quit)
# Maximize icon
self.maxBtn = QPushButton(self)
self.maxBtn.setGeometry(self,336,0,32,32)
self.maxBtn.setFlat(True)
self.maxBtn.setStyleSheet('QPushButton{background-color: rgba(0,0,0,0.0)}')
self.maxBtn.setIcon(QIcon('img/max.png'))
self.maxBtn.setIconSize(QSize(14,14))
# Minimize Incon
self.minBtn = QPushButton(self)
self.minBtn.setGeometry(304,0,32,32)
self.minBtn.setFlat(True)
self.minBtn.setStyleSheet('QPushButton{background-color: rgba(0,0,0,0.0)}')
self.minBtn.setIcon(QIcon('img/min.png'))
self.minBtn.setIconSize(QSize(10,10))
def main():
app = QApplication()
win = Main()
win.show()
app.exec_()
if __name__ == "__main__":
main()
I want to fixed navbar on the left. So, I create instance of QVBoxLayout and add widget to my Layout. and I had searched google, stackoverflow. i Don't get any information about my problem
but I don't know how to set layout widget. please teach me. Thank you.
if you don't understand my text please tell me i will describe that
Version:
PySide 5.14.2.1
Python 3.7.7

The layouts are not visual elements, so they do not have any geometric element associated with them, such as the width size, the layout is a handle of size and positions.
In this case the solution is to establish a container with a fixed size and in that container place the buttons with the help of a layout:
class Main(QDialog):
def __init__(self):
super(Main, self).__init__()
self.ui()
# Group Of Drage Event
def mousePressEvent(self, event):
self.offset = event.pos()
def mouseMoveEvent(self, e):
x = e.globalX()
y = e.globalY()
x_w = self.offset.x()
y_w = self.offset.y()
self.move(x - x_w, y - y_w)
def ui(self):
# TitleBar
self.setWindowFlags(Qt.FramelessWindowHint)
# Window Size
self.setGeometry(600, 300, 400, 500)
# Window Background Color
self.BackGroundColor = QPalette()
self.BackGroundColor.setColor(QPalette.Background, QColor(255, 255, 255))
self.setPalette(self.BackGroundColor)
# NavBar Button
self.btn = QPushButton("Test")
self.btn1 = QPushButton("Test1")
left_container = QWidget(self)
left_container.setFixedWidth(100)
# NavBar layout
self.layout = QVBoxLayout(left_container)
self.layout.addWidget(self.btn)
self.layout.addWidget(self.btn1)
hlay = QHBoxLayout(self)
hlay.addWidget(left_container)
hlay.addStretch()
# Close img
self.closeBtn = QPushButton(self)
self.closeBtn.setGeometry(368, 0, 32, 32)
self.closeBtn.setFlat(True)
self.closeBtn.setStyleSheet("QPushButton{background-color: rgba(0,0,0,0.0)}")
self.closeBtn.setIcon(QIcon("img/close.png"))
self.closeBtn.setIconSize(QSize(10, 10))
self.closeBtn.clicked.connect(QCoreApplication.instance().quit)
# Maximize icon
self.maxBtn = QPushButton(self)
self.maxBtn.setGeometry(336, 0, 32, 32)
self.maxBtn.setFlat(True)
self.maxBtn.setStyleSheet("QPushButton{background-color: rgba(0,0,0,0.0)}")
self.maxBtn.setIcon(QIcon("img/max.png"))
self.maxBtn.setIconSize(QSize(14, 14))
# Minimize Incon
self.minBtn = QPushButton(self)
self.minBtn.setGeometry(304, 0, 32, 32)
self.minBtn.setFlat(True)
self.minBtn.setStyleSheet("QPushButton{background-color: rgba(0,0,0,0.0)}")
self.minBtn.setIcon(QIcon("img/min.png"))
self.minBtn.setIconSize(QSize(10, 10))

Related

Using QStackedWidget in PyQt5

I have QStackedWidget in ApplicationWindow class and buttons which are going to point to different QWidgets in MenuWindow. I need a help with writing a function which would change the CurrentWidget according to button clicked - e.g. login_button would change the CurrentWidget to LoginWindow.
When trying to do it myself I ran into recursion problems as I have just started with learning Python.
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
import sys
class ApplicationWindow(QWidget):
def __init__(self):
super(ApplicationWindow, self).__init__()
# stack = Controller()
self.menu = MenuWindow()
self.login = LoginWindow()
self.setGeometry(0, 0, 800, 600)
self.setWindowTitle('Finance tracker')
self.setAutoFillBackground(True)
p = self.palette()
p.setColor(self.backgroundRole(), Qt.green)
self.setPalette(p)
self.stack = QStackedWidget()
self.stack.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Maximum)
self.stack.addWidget(self.menu)
self.stack.addWidget(self.login)
self.stack.setCurrentWidget(self.menu)
layout = QVBoxLayout()
layout.addWidget(self.stack)
layout.setAlignment(Qt.AlignCenter)
self.setLayout(layout)
class MenuWindow(QWidget):
def __init__(self):
super(MenuWindow, self).__init__()
self.setGeometry(0, 0, 250, 200)
box = QVBoxLayout()
self.setAutoFillBackground(True)
p = self.palette()
p.setColor(self.backgroundRole(), Qt.red)
self.setPalette(p)
label = QLabel('Welcome to finance tracker')
label.setStyleSheet('font: 24pt')
box.addWidget(label, alignment=Qt.AlignCenter)
login_button = QPushButton('Login')
login_button.clicked.connect(qApp.exit)
new_button = QPushButton('Create a new account')
new_button.clicked.connect(qApp.exit)
exit_button = QPushButton('Exit')
exit_button.clicked.connect(qApp.exit)
for button in [login_button, new_button, exit_button]:
button.setStyleSheet('font: 14pt')
button.setFixedSize(200, 50)
box.addWidget(button, alignment=Qt.AlignCenter)
self.setLayout(box)
self.show()
class LoginWindow(QWidget):
def __init__(self):
super(LoginWindow, self).__init__()
self.setGeometry(0, 0, 10, 250)
self.setAutoFillBackground(True)
p = self.palette()
p.setColor(self.backgroundRole(), Qt.blue)
self.setPalette(p)
label = QLabel('Welcome to finance tracker')
box = QVBoxLayout()
box.addWidget(label)
self.setLayout(box)
self.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
window = ApplicationWindow()
window.show()
sys.exit(app.exec())
Since you are using QPushButtons to switch pages I would add them to a QButtonGroup. This way you can connect the QButtonGroup.buttonClicked[int] signal to QStackedWidget.setCurrentIndex. Keep a pointer to the QButtonGroup in your MenuWindow.
class MenuWindow(QWidget):
def __init__(self):
...
login_button = QPushButton('Login')
new_button = QPushButton('Create a new account')
exit_button = QPushButton('Exit')
exit_button.clicked.connect(qApp.exit)
self.btn_group = QButtonGroup()
for i, button in enumerate([login_button, new_button, exit_button]):
button.setStyleSheet('font: 14pt')
button.setFixedSize(200, 50)
box.addWidget(button, alignment=Qt.AlignCenter)
self.btn_group.addButton(button)
self.btn_group.setId(button, i + 1)
...
And now you can connect the signal and slot in your ApplicationWindow.
class ApplicationWindow(QWidget):
def __init__(self):
...
self.menu.btn_group.buttonClicked[int].connect(self.stack.setCurrentIndex)

Create a full Screen Button in PYQT5

Start of the application
Plot the Graph
Full Screen
I have an application with 4 Box on the main window, and I want to had a full screen button in a windows which plot some graph, like on the Pictures on the top.
I first try a method to creating a fullScreen function in my code, linked to the button, but it is no work.
Here is my try :
class mainApplication(QWidget):
def __init__(self, parent=None):
super(mainApplication, self).__init__(parent)
self.layoutMap = {}
self.buttonMap = {}
# Figure Bottom Right
self.figure = plt.figure(figsize=(15,5))
self.figure.set_facecolor('0.915')
self.canvas = FigureCanvas(self.figure)
# Main Figure
self.setGeometry(600, 300, 1000, 600)
self.topLeft()
self.topRight()
self.bottomLeft()
self.bottomRight()
mainLayout = QGridLayout()
mainLayout.addWidget(self.topLeftBox, 1, 0)
mainLayout.addWidget(self.topRightBox, 1, 1)
mainLayout.addWidget(self.bottomLeftBox, 2, 0)
mainLayout.addWidget(self.bottomRightBox, 2, 1)
mainLayout.setRowStretch(1, 1)
mainLayout.setRowStretch(2, 1)
mainLayout.setColumnStretch(0, 1)
mainLayout.setColumnStretch(1, 1)
self.saveLayout(mainLayout, "main")
self.setLayout(mainLayout)
self.setWindowTitle("Title")
QApplication.setStyle("Fusion")
self.show()
def bottomRight(self):
self.bottomRightBox = QGroupBox("Bottom Right")
# Create Select Button
chooseButton = QPushButton("Select")
chooseButton.setMaximumWidth(100)
chooseButton.setMaximumHeight(20)
self.saveButton(chooseButton)
chooseButton.clicked.connect(self.selectFunction)
# Create Full Screen Button
fullScreenButton = QPushButton("Full")
fullScreenButton.setMaximumWidth(100)
fullScreenButton.setMaximumHeight(20)
self.saveButton(fullScreenButton)
fullScreenButton.clicked.connect(self.swichFullScreen)
# Create Layout
layout = QVBoxLayout()
layout.addWidget(self.canvas)
layout.addWidget(chooseButton)
layout.addWidget(fullScreenButton)
layout.addStretch(1)
self.saveLayout(layout, "full")
# Add Layout to GroupBox
self.bottomRightBox.setLayout(layout)
def selectFunction(self):
# Select Data
filePath, _ = QtWidgets.QFileDialog.getOpenFileName(self, 'Open file', '/Data/')
df = pd.read_csv(str(filePath))
x = df.x.tolist()
y = df.y.tolist()
# Create Figure
self.figure.clf()
ax = self.figure.add_subplot(111)
ax.plot(x, y)
ax.set_facecolor('0.915')
ax.set_title('Graphique')
# Draw Graph
self.canvas.draw()
def saveLayout(self,obj, text):
self.layoutMap[text] = obj
def findLayout(self,text):
return self.layoutMap[text]
def saveButton(self,obj):
self.buttonMap[obj.text()] = obj
def findButton(self,text):
return self.buttonMap[text]
def swichFullScreen(self):
self.setLayout(self.findLayout("full"))
self.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
mainWindow = mainApplication()
sys.exit(app.exec_())
Have you an idea? because for example, if in my initialization I don't do :
self.setLayout(mainLayout)
but :
swichFullScreen()
I have the result that I want, so why call this fonction after the creation of my main layout don't work?
Moreover, I have try an other thing adapter from this : PyQt: Change GUI Layout after button is clicked
But it still not worked because when I clic on the button "full", it switch very well, but the normalWindow object has been delete so the button select stop to work.
If you have a solution for my first idea, I prefer because it avoid the creation of other class, but if it is not possible and that you find a solution for the second solution to avoid the destruction of the object, I take it too.
Here the code for my second solution :
class fullScreenApplication(QWidget):
def __init__(self, parent=None):
super(fullScreenApplication, self).__init__(parent)
self.setGeometry(600, 300, 1000, 600)
class MainWindow(QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.setGeometry(600, 300, 1000, 600)
self.normalWindows()
def normalWindows(self):
self.normalBox = mainApplication(self)
self.setCentralWidget(self.normalBox)
self.normalBox.findButton("Full").clicked.connect(self.fullScreenWindow)
self.show()
def fullScreenWindow(self):
self.FullBox = fullScreenApplication(self)
self.FullBox.setLayout(self.normalBox.findLayout("full"))
self.normalBox.findButton("Full").clicked.connect(self.normalWindows)
self.normalBox.findButton("Select").clicked.connect(self.normalBox.selectFunction)
self.setCentralWidget(self.FullBox)
self.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
mainWindow = MainWindow()
sys.exit(app.exec_())
Thank you
Try it:
import sys
import pandas as pd
import matplotlib.pyplot as plt
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.figure import Figure
class mainApplication(QWidget):
def __init__(self, parent=None):
super(mainApplication, self).__init__(parent)
self.layoutMap = {}
self.buttonMap = {}
# Figure Bottom Right
self.figure = plt.figure(figsize=(15,5))
self.figure.set_facecolor('0.915')
self.canvas = FigureCanvas(self.figure)
# Main Figure
# self.setGeometry(600, 300, 1000, 600)
self.topLeftBox = self.topLeft()
self.topRightBox = self.topRight()
self.bottomLeftBox = self.bottomLeft()
self.bottomRight()
self.mainLayout = QGridLayout()
self.mainLayout.addWidget(self.topLeftBox, 1, 0)
self.mainLayout.addWidget(self.topRightBox, 1, 1)
self.mainLayout.addWidget(self.bottomLeftBox, 2, 0)
self.mainLayout.addWidget(self.bottomRightBox, 2, 1)
self.mainLayout.setRowStretch(1, 1)
self.mainLayout.setRowStretch(2, 1)
self.mainLayout.setColumnStretch(0, 1)
self.mainLayout.setColumnStretch(1, 1)
self.saveLayout(self.mainLayout, "main")
self.setLayout(self.mainLayout)
self.setWindowTitle("Title")
QApplication.setStyle("Fusion")
# self.show()
def bottomRight(self):
self.bottomRightBox = QGroupBox("Bottom Right")
# Create Select Button
chooseButton = QPushButton("Select")
chooseButton.setMaximumWidth(100)
chooseButton.setMaximumHeight(20)
self.saveButton(chooseButton)
chooseButton.clicked.connect(self.selectFunction)
# Create Full Screen Button
self.fullScreenButton = QPushButton("Full")
self.fullScreenButton.setMaximumWidth(100)
self.fullScreenButton.setMaximumHeight(20)
self.saveButton(self.fullScreenButton)
self.fullScreenButton.clicked.connect(self.swichFullScreen)
# Create Layout
layout = QVBoxLayout()
layout.addWidget(self.canvas)
layout.addWidget(chooseButton)
layout.addWidget(self.fullScreenButton)
layout.addStretch(1)
self.saveLayout(layout, "full")
# Add Layout to GroupBox
self.bottomRightBox.setLayout(layout)
def selectFunction(self):
# Select Data
filePath, _ = QFileDialog.getOpenFileName(self, 'Open file', '/Data/')
df = pd.read_csv(str(filePath))
x = df.x.tolist()
y = df.y.tolist()
# Create Figure
self.figure.clf()
ax = self.figure.add_subplot(111)
ax.plot(x, y)
ax.set_facecolor('0.915')
ax.set_title('Graphique')
# Draw Graph
self.canvas.draw()
def saveLayout(self,obj, text):
self.layoutMap[text] = obj
def findLayout(self,text):
return self.layoutMap[text]
def saveButton(self,obj):
self.buttonMap[obj.text()] = obj
def findButton(self,text):
return self.buttonMap[text]
def swichFullScreen(self):
# self.setLayout(self.findLayout("full")) # ---
# self.show() # ---
# +++ vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
if self.sender().text()== "Full":
self.topLeftBox.hide()
self.topRightBox.hide()
self.bottomLeftBox.hide()
self.bottomRightBox.hide()
self.mainLayout.addWidget(self.bottomRightBox, 0, 0, 1, 2)
self.bottomRightBox.show()
self.fullScreenButton.setText("NoFull")
else:
self.bottomRightBox.hide()
self.topLeftBox.show()
self.topRightBox.show()
self.bottomLeftBox.show()
self.mainLayout.addWidget(self.bottomRightBox, 2, 1)
self.bottomRightBox.show()
self.fullScreenButton.setText("Full")
def topLeft(self):
textEdit = QTextEdit()
return textEdit
def topRight(self):
textEdit = QTextEdit()
return textEdit
def bottomLeft(self):
textEdit = QTextEdit()
return textEdit
# +++ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
if __name__ == '__main__':
app = QApplication(sys.argv)
mainWindow = mainApplication()
mainWindow.setGeometry(200, 100, 1000, 600)
mainWindow.show()
sys.exit(app.exec_())

GridLayout and VerticalLayout in PyQT5

I am new to PyQT5 in Python2.7.
I like to have Verticle Layout with two components.
The first area is for Dispaly and the second area is for Control Widgets.
Now problem is (1)Control Widgets are not equally spaced and (2)First area needs more space than the second area.
How can I do that?
My code is as follow.
class Thread(QThread):
changePixmap = pyqtSignal(QImage)
def run(self):
cap = cv2.VideoCapture(0)
while True:
ret, frame = cap.read()
if ret:
rgbImage = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
convertToQtFormat = QImage(rgbImage.data, rgbImage.shape[1], rgbImage.shape[0], QImage.Format_RGB888)
p = convertToQtFormat.scaled(640, 480, Qt.KeepAspectRatio)
self.changePixmap.emit(p)
class PlayStreaming(QWidget):
def __init__(self):
super(PlayStreaming,self).__init__()
self.initUI()
#pyqtSlot(QImage)
def setImage(self, image):
self.label.setPixmap(QPixmap.fromImage(image))
def initUI(self):
self.setWindowTitle("Image")
self.setGeometry(100, 100, 600, 400)
self.resize(1800, 1200)
# create a label
self.label = QLabel(self)
self.label.move(280, 120)
self.label.resize(640, 480)
th = Thread(self)
th.changePixmap.connect(self.setImage)
th.start()
class UIWidget(QWidget):
def __init__(self, parent):
super(QWidget, self).__init__(parent)
self.layout = QVBoxLayout(self)
# Initialize tab screen
self.tabs = QTabWidget()
self.tab1 = QWidget()
self.tab2 = QWidget()
self.tab3 = QWidget()
self.tabs.resize(800,600)
# Add tabs
self.tabs.addTab(self.tab1,"Face")
self.tabs.addTab(self.tab2,"Human")
self.tabs.addTab(self.tab3,"Vehicle")
# Create first tab
self.createGridLayout()
self.tab1.layout = QVBoxLayout(self)
self.display=PlayStreaming()
self.tab1.layout.addWidget(self.display)
self.tab1.layout.addWidget(self.horizontalGroupBox)
self.tab1.setLayout(self.tab1.layout)
# Add tabs to widget
self.layout.addWidget(self.tabs)
self.setLayout(self.layout)
def createGridLayout(self):
self.horizontalGroupBox = QGroupBox("Control")
layout = QGridLayout()
layout.setColumnStretch(2, 3)
layout.addWidget(QPushButton('Test'),0,0)
layout.addWidget(QPushButton('Run'),0,1)
layout.addWidget(QPushButton('Set Faces'),0,2)
layout.addWidget(QPushButton('Recognize'),1,0)
layout.addWidget(QPushButton('Rescale'),1,1)
layout.addWidget(QPushButton('FacePose'),1,2)
self.horizontalGroupBox.setLayout(layout)
The current status is
How can I do that?
You must use the strech to set the weights, by default the stretch of each widget is 0 so you just need to set a stretch of 1 to self.display. On the other hand, it is not necessary to use setColumnStretch() since by default all buttons will have the same size:
from PyQt5 import QtCore, QtGui, QtWidgets
import cv2
class Thread(QtCore.QThread):
changePixmap = QtCore.pyqtSignal(QtGui.QImage)
def run(self):
cap = cv2.VideoCapture(0)
while True:
ret, frame = cap.read()
if ret:
rgbImage = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
convertToQtFormat = QtGui.QImage(rgbImage.data, rgbImage.shape[1], rgbImage.shape[0], QtGui.QImage.Format_RGB888)
p = convertToQtFormat.scaled(640, 480, QtCore.Qt.KeepAspectRatio)
self.changePixmap.emit(p)
class PlayStreaming(QtWidgets.QWidget):
def __init__(self):
super(PlayStreaming,self).__init__()
self.initUI()
#QtCore.pyqtSlot(QtGui.QImage)
def setImage(self, image):
self.label.setPixmap(QtGui.QPixmap.fromImage(image))
def initUI(self):
self.setWindowTitle("Image")
# create a label
self.label = QtWidgets.QLabel(self)
th = Thread(self)
th.changePixmap.connect(self.setImage)
th.start()
lay = QtWidgets.QVBoxLayout(self)
lay.addWidget(self.label, alignment=QtCore.Qt.AlignCenter)
class UIWidget(QtWidgets.QWidget):
def __init__(self, parent=None):
super(UIWidget, self).__init__(parent)
# Initialize tab screen
self.tabs = QtWidgets.QTabWidget()
self.tab1 = QtWidgets.QWidget()
self.tab2 = QtWidgets.QWidget()
self.tab3 = QtWidgets.QWidget()
# Add tabs
self.tabs.addTab(self.tab1,"Face")
self.tabs.addTab(self.tab2,"Human")
self.tabs.addTab(self.tab3,"Vehicle")
# Create first tab
self.createGridLayout()
self.tab1.layout = QtWidgets.QVBoxLayout()
self.display = PlayStreaming()
self.tab1.layout.addWidget(self.display, stretch=1)
self.tab1.layout.addWidget(self.horizontalGroupBox)
self.tab1.setLayout(self.tab1.layout)
# Add tabs to widget
layout = QtWidgets.QVBoxLayout(self)
layout.addWidget(self.tabs)
def createGridLayout(self):
self.horizontalGroupBox = QtWidgets.QGroupBox("Control")
layout = QtWidgets.QGridLayout()
layout.addWidget(QtWidgets.QPushButton('Test'),0,0)
layout.addWidget(QtWidgets.QPushButton('Run'),0,1)
layout.addWidget(QtWidgets.QPushButton('Set Faces'),0,2)
layout.addWidget(QtWidgets.QPushButton('Recognize'),1,0)
layout.addWidget(QtWidgets.QPushButton('Rescale'),1,1)
layout.addWidget(QtWidgets.QPushButton('FacePose'),1,2)
self.horizontalGroupBox.setLayout(layout)
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
w = UIWidget()
w.show()
sys.exit(app.exec_())

Pixmap image size in Qlabel

I'm trying to get an image to fit my label entirely without using setScaledContents(True) since I'd like my ImageGrab to have the exact same dimensions as the QLabel space.
I use a PIL ImageGrab with a bbox. if I chance the parameters to a wider width and higher height it will crash the program without any errors. I have attached a picture where the Image in the Label is localed left center. I'd like it to the top left. So that it can expand down and to the right if I increased the size.
But I am curious as to why I am unable to increase the size of the bbox. (0, 0, 400, 220) works fine but (0, 0, 420, 220) will not upload the Image and closes down the GUI without any errors.
I'd like to have a ImageGrab with bbox (0, 0, 800, 700) and a QLabel with size(800, 700) so it can fit it perfectly.
class Main(QMainWindow):
def __init__(self, parent=None):
QWidget.__init__(self, parent)
self.setGeometry(200, 200, 1000, 700)
self.setWindowTitle('threads')
self.mainFrame = QFrame(self)
self.mainFrame.resize(1000, 650)
self.mainFrame.move(0, 50)
self.mainFrame.setStyleSheet("background-color: rbg(50, 50, 50)")
self.testButton = QPushButton("Click", self)
self.testButton.resize(500,30)
self.connect(self.testButton, SIGNAL("clicked()"), self.Capture)
self.label_ = QLabel(self.mainFrame)
self.label_.move(10, 10)
self.label_.resize(980, 630)
self.label_.setStyleSheet("background-color: rbg(150, 150, 150)")
#pyqtSlot(QImage)
def ChangeFrame(self, image):
pixmap = QPixmap.fromImage(image)
self.label_.setPixmap(pixmap)
def Capture(self):
self.thread_ = CaptureScreen()
self.connect(self.thread_, SIGNAL("ChangeFrame(QImage)"), self.ChangeFrame, Qt.QueuedConnection)
self.thread_.start()
class CaptureScreen(QThread):
pixmap = pyqtSignal(QImage)
def __init__(self, parent = None):
QThread.__init__(self)
def __del__(self):
print("?????")
self.exiting = True
self.wait()
def run(self):
while(True):
time.sleep(1/60)
img = ImageGrab.grab(bbox=(0, 0, 420, 220))
frame = ImageQt(img)
frame = QImage(frame)
self.emit( SIGNAL("ChangeFrame(QImage)"), frame)
The solution is to use layouts, and set the alignment in QtCore.Qt.AlignTop | QtCore.Qt.AlignLeft.
I also recommend using the new connection syntax, on the other hand if you are going to inherit from QMainWindow in the constructor you must call it. And finally when you use QMainWindow you must set a central widget.
import time
from PyQt4 import QtCore, QtGui
from PIL import ImageGrab, ImageQt
class Main(QtGui.QMainWindow):
def __init__(self, parent=None):
QtGui.QMainWindow.__init__(self, parent)
self.setGeometry(200, 200, 1000, 700)
self.setWindowTitle('threads')
main_widget = QtGui.QWidget()
self.setCentralWidget(main_widget)
lay = QtGui.QVBoxLayout(main_widget)
self.testButton = QtGui.QPushButton("Click")
self.testButton.setFixedHeight(30)
self.testButton.clicked.connect(self.capture)
mainFrame = QtGui.QFrame()
mainFrame.setStyleSheet("background-color: rbg(50, 50, 50)")
_lay = QtGui.QVBoxLayout(mainFrame)
_lay.setContentsMargins(0, 0, 0, 0)
self.label_ = QtGui.QLabel()
_lay.addWidget(self.label_, 0, QtCore.Qt.AlignTop|QtCore.Qt.AlignLeft)
lay.addWidget(self.testButton)
lay.addWidget(mainFrame)
#QtCore.pyqtSlot(QtGui.QImage)
def changeFrame(self, image):
pixmap = QtGui.QPixmap.fromImage(image)
self.label_.setPixmap(pixmap)
#QtCore.pyqtSlot()
def capture(self):
self.thread_ = CaptureScreen()
self.thread_.changedFrame.connect(self.changeFrame, QtCore.Qt.QueuedConnection)
self.thread_.start()
self.testButton.setDisabled(True)
class CaptureScreen(QtCore.QThread):
changedFrame = QtCore.pyqtSignal(QtGui.QImage)
def __del__(self):
print("?????")
self.exiting = True
self.quit()
self.wait()
def run(self):
while True:
time.sleep(1/60)
w, h = 420, 220
img = ImageGrab.grab(bbox=(0, 0, w, h))
frame = ImageQt.toqimage(img)
self.changedFrame.emit(QtGui.QImage(frame))
if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
w = Main()
w.show()
sys.exit(app.exec_())

PySide/PyQt Overlay widget

I am trying to achieve something like this in PySide: https://codepen.io/imprakash/pen/GgNMXO
What I want to do is create a child window frameless with a black overlay below.
I didn't succeed to create a child window frameless and the overlay...
This is a base code to replicate the HTML:
from PySide import QtCore, QtGui
import sys
class MainWindow(QtGui.QWidget):
def __init__(self):
QtGui.QWidget.__init__(self)
self.resize(800, 500)
self.button = QtGui.QPushButton("Click Me")
self.setLayout(QtGui.QVBoxLayout())
self.layout().addWidget(self.button)
# Connections
self.button.clicked.connect(self.displayOverlay)
def displayOverlay(self):
popup = QtGui.QDialog(self)
popup.setWindowFlags(QtCore.Qt.FramelessWindowHint)
popup.setLayout(QtGui.QHBoxLayout())
popup.layout().addWidget(QtGui.QLabel("HI"))
popup.show()
print "clicked"
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
If you comment the line with the FramelessWindowHint, the window comes, else nothing happen...
I really hope that someone could help me. Thank you for the time you spent to read my question.
I'll be using PyQt5 for this explanation. It might have some differences to PySide (which I'm not sure if its still maintained) and PyQt4, but it shouldn't be too hard to convert.
The following example has a parent widget which a few buttons. One of them (the obvious one) calls for the popup. I've prepared the example to deal with the parent resize but have not made any code regarding mouse events of dragging the popup (see mouseMoveEvent and mouseReleaseEvent for that).
So here is the code:
import sys
from PyQt5 import QtWidgets, QtCore, QtGui
class TranslucentWidgetSignals(QtCore.QObject):
# SIGNALS
CLOSE = QtCore.pyqtSignal()
class TranslucentWidget(QtWidgets.QWidget):
def __init__(self, parent=None):
super(TranslucentWidget, self).__init__(parent)
# make the window frameless
self.setWindowFlags(QtCore.Qt.FramelessWindowHint)
self.setAttribute(QtCore.Qt.WA_TranslucentBackground)
self.fillColor = QtGui.QColor(30, 30, 30, 120)
self.penColor = QtGui.QColor("#333333")
self.popup_fillColor = QtGui.QColor(240, 240, 240, 255)
self.popup_penColor = QtGui.QColor(200, 200, 200, 255)
self.close_btn = QtWidgets.QPushButton(self)
self.close_btn.setText("x")
font = QtGui.QFont()
font.setPixelSize(18)
font.setBold(True)
self.close_btn.setFont(font)
self.close_btn.setStyleSheet("background-color: rgb(0, 0, 0, 0)")
self.close_btn.setFixedSize(30, 30)
self.close_btn.clicked.connect(self._onclose)
self.SIGNALS = TranslucentWidgetSignals()
def resizeEvent(self, event):
s = self.size()
popup_width = 300
popup_height = 120
ow = int(s.width() / 2 - popup_width / 2)
oh = int(s.height() / 2 - popup_height / 2)
self.close_btn.move(ow + 265, oh + 5)
def paintEvent(self, event):
# This method is, in practice, drawing the contents of
# your window.
# get current window size
s = self.size()
qp = QtGui.QPainter()
qp.begin(self)
qp.setRenderHint(QtGui.QPainter.Antialiasing, True)
qp.setPen(self.penColor)
qp.setBrush(self.fillColor)
qp.drawRect(0, 0, s.width(), s.height())
# drawpopup
qp.setPen(self.popup_penColor)
qp.setBrush(self.popup_fillColor)
popup_width = 300
popup_height = 120
ow = int(s.width()/2-popup_width/2)
oh = int(s.height()/2-popup_height/2)
qp.drawRoundedRect(ow, oh, popup_width, popup_height, 5, 5)
font = QtGui.QFont()
font.setPixelSize(18)
font.setBold(True)
qp.setFont(font)
qp.setPen(QtGui.QColor(70, 70, 70))
tolw, tolh = 80, -5
qp.drawText(ow + int(popup_width/2) - tolw, oh + int(popup_height/2) - tolh, "Yep, I'm a pop up.")
qp.end()
def _onclose(self):
print("Close")
self.SIGNALS.CLOSE.emit()
class ParentWidget(QtWidgets.QWidget):
def __init__(self, parent=None):
super(ParentWidget, self).__init__(parent)
self._popup = QtWidgets.QPushButton("Gimme Popup!!!")
self._popup.setFixedSize(150, 40)
self._popup.clicked.connect(self._onpopup)
self._other1 = QtWidgets.QPushButton("A button")
self._other2 = QtWidgets.QPushButton("A button")
self._other3 = QtWidgets.QPushButton("A button")
self._other4 = QtWidgets.QPushButton("A button")
hbox = QtWidgets.QHBoxLayout()
hbox.addWidget(self._popup)
hbox.addWidget(self._other1)
hbox.addWidget(self._other2)
hbox.addWidget(self._other3)
hbox.addWidget(self._other4)
self.setLayout(hbox)
self._popframe = None
self._popflag = False
def resizeEvent(self, event):
if self._popflag:
self._popframe.move(0, 0)
self._popframe.resize(self.width(), self.height())
def _onpopup(self):
self._popframe = TranslucentWidget(self)
self._popframe.move(0, 0)
self._popframe.resize(self.width(), self.height())
self._popframe.SIGNALS.CLOSE.connect(self._closepopup)
self._popflag = True
self._popframe.show()
def _closepopup(self):
self._popframe.close()
self._popflag = False
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
main = ParentWidget()
main.resize(500, 500)
main.show()
sys.exit(app.exec_())
Which results in the following:
The logic is the following. You create an empty Widget and manually draw the background and popup (paintEvent). You add a button for closing the popup. For this you build a Signal and let the parent widget do the closing. This is important because you need to make the parent widget control some important elements of the popup (such as closing, resizng, etc.). You can add far more complexity but hopefully the example will suffice for starters.
Thanks to armatita, I succeed to get what I wanted. For now, there are some issues but it works and I get the result that I wanted.
I give you the code to the next who will be looking for the same thing.
from PySide import QtCore, QtGui
import sys
class CtmWidget(QtGui.QWidget):
def __init__(self, parent = None):
QtGui.QWidget.__init__(self, parent)
self.button = QtGui.QPushButton("Close Overlay")
self.setLayout(QtGui.QHBoxLayout())
self.layout().addWidget(self.button)
self.button.clicked.connect(self.hideOverlay)
def paintEvent(self, event):
painter = QtGui.QPainter()
painter.begin(self)
painter.setRenderHint(QtGui.QPainter.Antialiasing)
path = QtGui.QPainterPath()
path.addRoundedRect(QtCore.QRectF(self.rect()), 10, 10)
mask = QtGui.QRegion(path.toFillPolygon().toPolygon())
pen = QtGui.QPen(QtCore.Qt.white, 1)
painter.setPen(pen)
painter.fillPath(path, QtCore.Qt.white)
painter.drawPath(path)
painter.end()
def hideOverlay(self):
self.parent().hide()
class Overlay(QtGui.QWidget):
def __init__(self, parent, widget):
QtGui.QWidget.__init__(self, parent)
palette = QtGui.QPalette(self.palette())
palette.setColor(palette.Background, QtCore.Qt.transparent)
self.setPalette(palette)
self.widget = widget
self.widget.setParent(self)
def paintEvent(self, event):
painter = QtGui.QPainter()
painter.begin(self)
painter.setRenderHint(QtGui.QPainter.Antialiasing)
painter.fillRect(event.rect(), QtGui.QBrush(QtGui.QColor(0, 0, 0, 127)))
painter.end()
def resizeEvent(self, event):
position_x = (self.frameGeometry().width()-self.widget.frameGeometry().width())/2
position_y = (self.frameGeometry().height()-self.widget.frameGeometry().height())/2
self.widget.move(position_x, position_y)
event.accept()
class MainWindow(QtGui.QWidget):
def __init__(self):
QtGui.QWidget.__init__(self)
self.resize(800, 500)
self.button = QtGui.QPushButton("Click Me")
self.setLayout(QtGui.QVBoxLayout())
self.layout().addWidget(self.button)
self.popup = Overlay(self, CtmWidget())
self.popup.hide()
# Connections
self.button.clicked.connect(self.displayOverlay)
def displayOverlay(self):
self.popup.show()
print "clicked"
def resizeEvent(self, event):
self.popup.resize(event.size())
event.accept()
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
Once again thank you both of you(ymmx and armatita) to spend time on my issue.
did you try replacing popup.show() by popup.exec_()? and remove self as a parameter of the Qdialog? I change QDialog to QmessageBox to be able to quit the subwindow but it still work with the QDialog.
popup = QMessageBox()
popup.setWindowFlags( Qt.FramelessWindowHint)
popup.setLayout( QHBoxLayout())
popup.layout().addWidget( QLabel("HI"))
popup.exec_()
update
class Popup(QDialog ):
def __init__(self):
super().__init__()
self.setWindowFlags( Qt.CustomizeWindowHint)
self.setLayout( QHBoxLayout())
Button_close = QPushButton('close')
self.layout().addWidget( QLabel("HI"))
self.layout().addWidget( Button_close)
Button_close.clicked.connect( self.close )
self.exec_()
print("clicked")
def mousePressEvent(self, event):
self.oldPos = event.globalPos()
def mouseMoveEvent(self, event):
delta = QPoint (event.globalPos() - self.oldPos)
#print(delta)
self.move(self.x() + delta.x(), self.y() + delta.y())
self.oldPos = event.globalPos()
class MainWindow( QWidget):
def __init__(self):
QWidget.__init__(self)
self.resize(800, 500)
self.button = QPushButton("Click Me")
self.setLayout( QVBoxLayout())
self.layout().addWidget(self.button)
# Connections
self.button.clicked.connect(self.displayOverlay)
def displayOverlay(self):
Popup( )
if __name__ == "__main__":
app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())

Categories

Resources