Is there an attribute to position subwindows in qmdiarea? I’m trying to center subwindow in middle of mainwindow on startup (mdiarea)
I’m working on a mcve but haven’t finished it, wanted to see if anyone has tried doing this, and how they did it
Subwindows are randomly placed on startup when initialized
class App(QMainWindow, Ui_MainWindow):
def __init__(self, parent=None):
QMainWindow.__init__(self, parent=parent)
self.setupUi(self)
self.screenShape = QDesktopWidget().screenGeometry()
self.width = self.screenShape.width()
self.height = self.screenShape.height()
self.resize(self.width * .6, self.height * .6)
self.new = []
#calls GUI's in other modules
self.lw = Login()
self.vs = VS()
self.ms = MS()
self.hw = HomeWindow()
self.mw = MainWindow()
self.ga = GA()
self.sGUI = Settings()
# shows subwindow
self.CreateLogin()
self.CreateVS()
self.CreateMS()
self.CreateGA()
self.CreateSettings()
def CreateLogin(self):
self.subwindow = QMdiSubWindow()
self.subwindow.setWidget(self.lw)
self.subwindow.setAttribute(Qt.WA_DeleteOnClose, True)
self.mdiArea.addSubWindow(self.subwindow)
self.subwindow.setMaximumSize(520, 300)
self.subwindow.setMinimumSize(520, 300)
self.lw.showNormal()
def CreateVS(self):
self.subwindow = QMdiSubWindow()
self.subwindow.setWidget(self.vs)
self.mdiArea.addSubWindow(self.subwindow)
self.vs.showMinimized()
def CreateMS(self):
self.subwindow = QMdiSubWindow()
self.subwindow.setWidget(self.ms)
self.mdiArea.addSubWindow(self.subwindow)
self.ms.showMinimized()
self.ms.tabWidget.setCurrentIndex(0)
def CreateGA(self):
self.subwindow = QMdiSubWindow()
self.subwindow.setWidget(self.ga)
self.mdiArea.addSubWindow(self.subwindow)
self.ga.showMinimized()
self.subwindow.setMaximumSize(820, 650)
def CreateSettings(self):
self.subwindow = QMdiSubWindow()
self.subwindow.setWidget(self.sGUI)
self.mdiArea.addSubWindow(self.subwindow)
self.sGUI.showMinimized()
def CreateWindow(self):
self.hw.pushButton.clicked.connect(self.vs.showNormal)
self.hw.pushButton_2.clicked.connect(self.Moduleprogram)
self.hw.pushButton_3.clicked.connect(self.ms.showNormal)
self.hw.pushButton_4.clicked.connect(self.ga.showNormal)
self.subwindow = QMdiSubWindow()
self.subwindow.setWindowFlags(Qt.CustomizeWindowHint | Qt.Tool)
self.subwindow.setWidget(self.hw)
self.subwindow.setMaximumSize(258, 264)
self.subwindow.move(self.newwidth*.35, self.newheight*.25)
self.mdiArea.addSubWindow(self.subwindow)
In Qt the geometry is only effective when the window is visible so if you want to center something it must be in the showEvent method. On the other hand to center the QMdiSubWindow you must first get the center of the viewport of the QMdiArea, and according to that modify the geometry of the QMdiSubWindow.
Because the code you provide is complicated to execute, I have created my own code
from PyQt5 import QtCore, QtGui, QtWidgets
import random
def create_widget():
widget = QtWidgets.QLabel(
str(random.randint(0, 100)), alignment=QtCore.Qt.AlignCenter
)
widget.setStyleSheet(
"""background-color: {};""".format(
QtGui.QColor(*random.sample(range(255), 3)).name()
)
)
widget.setMinimumSize(*random.sample(range(100, 300), 2))
return widget
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super().__init__(parent)
add_button = QtWidgets.QPushButton(
"Add subwindow", clicked=self.add_subwindow
)
self._mdiarea = QtWidgets.QMdiArea()
central_widget = QtWidgets.QWidget()
self.setCentralWidget(central_widget)
lay = QtWidgets.QVBoxLayout(central_widget)
lay.addWidget(add_button)
lay.addWidget(self._mdiarea)
self._is_first_time = True
for _ in range(4):
self.add_subwindow()
#QtCore.pyqtSlot()
def add_subwindow(self):
widget = create_widget()
subwindow = QtWidgets.QMdiSubWindow(self._mdiarea)
subwindow.setWidget(widget)
subwindow.setAttribute(QtCore.Qt.WA_DeleteOnClose, True)
subwindow.show()
self._mdiarea.addSubWindow(subwindow)
# self.center_subwindow(subwindow)
def showEvent(self, event):
if self.isVisible() and self._is_first_time:
for subwindow in self._mdiarea.subWindowList():
self.center_subwindow(subwindow)
self._is_first_time = False
def center_subwindow(self, subwindow):
center = self._mdiarea.viewport().rect().center()
geo = subwindow.geometry()
geo.moveCenter(center)
subwindow.setGeometry(geo)
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec_())
Update:
If you want the subwindow to be centered then with the following code you have to create a property center to True:
def add_subwindow(self):
widget = create_widget()
subwindow = QtWidgets.QMdiSubWindow(self._mdiarea)
subwindow.setWidget(widget)
subwindow.setAttribute(QtCore.Qt.WA_DeleteOnClose, True)
subwindow.show()
subwindow.setProperty("center", True) # <----
self._mdiarea.addSubWindow(subwindow)
def showEvent(self, event):
if self.isVisible() and self._is_first_time:
for subwindow in self._mdiarea.subWindowList():
if subwindow.property("center"): # <---
self.center_subwindow(subwindow)
self._is_first_time = False
Related
I'm trying to set a background image on a QWidget and have some QlineEdit on top of it.
So for know I have this code
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
import sys
class Model_GUI(QMainWindow):
def __init__(self, parent= None ):
super(Model_GUI, self).__init__()
self.left = 0
self.top = 0
self.width = 800
self.height = 800
self.resize(self.width,self.height)
GB = QGroupBox(" Gain ")
GB_layout = QHBoxLayout()
label = QLabel('A')
edit = QLineEdit('1')
GB_layout.addWidget(label)
GB_layout.addWidget(edit)
GB.setLayout(GB_layout)
GB2 = QGroupBox(" Gain ")
GB_layout2 = QHBoxLayout()
label2 = QLabel('A')
edit2 = QLineEdit('1')
GB_layout2.addWidget(label2)
GB_layout2.addWidget(edit2)
GB2.setLayout(GB_layout2)
#Graph
Graph = graph()
self.CentralWidget = QWidget()
self.globallayout = QHBoxLayout()
self.globallayout.addWidget(GB)
self.globallayout.addWidget(Graph)
self.globallayout.addWidget(GB2)
self.CentralWidget.setLayout(self.globallayout)
self.setCentralWidget(self.CentralWidget)
class graph(QWidget):
def __init__(self):
super().__init__()
self.setFixedSize(600,600)
oImage = QImage("img.png")
sImage = oImage.scaled(QSize(self.width(), self.height())) # resize Image to widgets size
palette = QPalette()
palette.setBrush(10, QBrush(sImage)) # 10 = Windowrole
self.setPalette(palette)
self.label1 = QLabel('Param1', self)
self.edit1 = QLineEdit('1', self)
self.label2 = QLabel('Param2', self)
self.edit2 = QLineEdit('10', self)
self.label1.move(50, 50)
self.edit1.move(500, 50)
self.label2.move(50, 500)
self.edit2.move(500, 500)
def main():
app = QApplication(sys.argv)
ex = Model_GUI(app)
ex.setWindowTitle('window')
ex.show()
sys.exit(app.exec_( ))
if __name__ == '__main__':
main()
but when I execute it I don't have the image in the QWidget (in the middle).
If I replace ex = Model_GUI(app)with ex = graph(), I have the correct expectation :
I don't understand why the image is correctly set when I'm using the QWidget alone but it isn't set right when I embedded it in a QMainWindow?
QWidgets use their QPalette.Window role only if they are top level widgets (as in "windows"), otherwise the parent background is used instead unless the autoFillBackground property (which is false by default) is true.
Just set the property in the widget initialization:
self.setAutoFillBackground(True)
I have several tabs and inside the "admin" tab I want to display two pages: one locked page (before entering credentials) and another unlocked page (after successful login). To do this, I'm using a QStackedWidget() to switch between the two pages. I have created a locked login screen but can't seem to move the object to the center of the page.
I have looked at moving widgets inside QStackedWidget and centering widgets in the center of the screen but my objects do not seem to change position. I've tried to move the entire internal widget using move() to the center of the screen using the desktop dimension and the parent widget to no avail. How would I be able to move the login fields to the center of the page? Thanks!
Current:
Desired:
Code:
from PyQt4 import QtGui, QtCore
# from load_CSS import load_CSS
# from widgets import UniversalPlotWidget
import sys
import time
def exit_application():
"""Exit program event handler"""
sys.exit(1)
class VerticalTabBar(QtGui.QTabBar):
def __init__(self, width, height, parent=None):
super(VerticalTabBar, self).__init__(parent)
self.width = width
self.height = height
def tabSizeHint(self, index):
return QtCore.QSize(self.width, self.height)
def paintEvent(self, event):
painter = QtGui.QStylePainter(self)
tab_options = QtGui.QStyleOptionTab()
for tab in range(self.count()):
self.initStyleOption(tab_options, tab)
painter.drawControl(QtGui.QStyle.CE_TabBarTabShape, tab_options)
painter.save()
size = tab_options.rect.size()
size.transpose()
rectangle = QtCore.QRect(QtCore.QPoint(), size)
rectangle.moveCenter(tab_options.rect.center())
tab_options.rect = rectangle
center = self.tabRect(tab).center()
painter.translate(center)
painter.rotate(90)
painter.translate(-center)
painter.drawControl(QtGui.QStyle.CE_TabBarTabLabel, tab_options);
painter.restore()
class TabWidget(QtGui.QTabWidget):
def __init__(self, *args, **kwargs):
QtGui.QTabWidget.__init__(self, *args, **kwargs)
self.setTabBar(VerticalTabBar(kwargs.pop('width'), kwargs.pop('height')))
self.setTabPosition(QtGui.QTabWidget.West)
self.setTabShape(QtGui.QTabWidget.Rounded)
class AdminTabWidget(QtGui.QWidget):
def __init__(self, parent=None):
super(AdminTabWidget, self).__init__(parent)
self.setWindowModality(QtCore.Qt.ApplicationModal)
self.setWindowFlags(QtCore.Qt.FramelessWindowHint)
self.admin_page_locked_init()
self.admin_page_unlocked_init()
self.admin_page_layout = QtGui.QGridLayout()
self.admin_page_switch = QtGui.QStackedWidget()
self.admin_page_switch.addWidget(self.admin_locked_tab)
self.admin_page_switch.addWidget(self.admin_unlocked_tab)
self.admin_page_switch.setCurrentIndex(0)
self.admin_page_layout.addWidget(self.admin_page_switch,0,0)
def admin_page_locked_init(self):
self.admin_locked_tab = QtGui.QWidget()
self.admin_locked_tab.setFixedSize(550,225)
self.admin_locked_layout = QtGui.QGridLayout()
self.username_label = QtGui.QLabel('Username: ')
self.username_field = QtGui.QLineEdit()
self.username_field.returnPressed.connect(self.verify_credentials)
self.space_label = QtGui.QLabel(' ')
self.space_label.setFixedHeight(25)
self.password_label = QtGui.QLabel('Password: ')
self.password_field = QtGui.QLineEdit()
self.password_field.returnPressed.connect(self.verify_credentials)
self.password_field.setEchoMode(QtGui.QLineEdit.Password)
self.verify_button = QtGui.QPushButton('Ok')
self.verify_button.clicked.connect(self.verify_credentials)
self.cancel_button = QtGui.QPushButton('Cancel')
self.cancel_button.clicked.connect(self.unauthorized)
self.status_label = QtGui.QLabel('')
self.status_label.setAlignment(QtCore.Qt.AlignCenter)
self.button_layout = QtGui.QGridLayout()
self.button_layout.addWidget(self.verify_button,0,0,1,1)
self.button_layout.addWidget(self.cancel_button,0,1,1,1)
self.admin_locked_layout.addWidget(self.username_label,0,0,1,1)
self.admin_locked_layout.addWidget(self.username_field,0,1,1,1)
self.admin_locked_layout.addWidget(self.space_label,1,0,1,3)
self.admin_locked_layout.addWidget(self.password_label,2,0,1,1)
self.admin_locked_layout.addWidget(self.password_field,2,1,1,1)
self.admin_locked_layout.addWidget(self.status_label,3,0,1,3)
self.admin_locked_layout.addLayout(self.button_layout,4,0,1,3)
self.admin_locked_tab.setLayout(self.admin_locked_layout)
def verify_credentials(self):
print('button pressed')
# Grab username/password from input fields
self.username = str(self.username_field.text())
self.password = str(self.password_field.text())
self.status_label.setText('Verifying')
self.status_label.setStyleSheet('QLabel {color: rgb(117,255,161)}')
self.spin(.001)
print('verified')
def spin(self, seconds):
"""Pause for set amount of seconds, replaces time.sleep so program doesnt stall"""
time_end = time.time() + seconds
while time.time() < time_end:
QtGui.QApplication.processEvents()
def unauthorized(self):
print('unauthorized')
self.status_label.setText('Invalid username and/or password')
self.status_label.setStyleSheet('QLabel {color: rgb(255,65,106)}')
def admin_page_unlocked_init(self):
self.admin_unlocked_tab = QtGui.QWidget()
admin_unlocked_layout = QtGui.QGridLayout()
admin_unlocked_button = QtGui.QPushButton('unlocked')
admin_unlocked_layout.addWidget(admin_unlocked_button)
self.admin_unlocked_tab.setLayout(admin_unlocked_layout)
def get_admin_page_layout(self):
return self.admin_page_layout
if __name__ == '__main__':
# Create main application window
app = QtGui.QApplication(sys.argv)
# app.setStyleSheet(load_CSS(1))
app.setStyle(QtGui.QStyleFactory.create("Cleanlooks"))
font = QtGui.QFont('Ubuntu', 20)
font.setWeight(70)
app.setFont(font)
screen_height = QtGui.QApplication.desktop().screenGeometry().height()
main_window_tab = TabWidget(width=300, height=screen_height/8)
main_window_tab.setWindowTitle("Tab Layout")
main_window_tab.setWindowFlags(QtCore.Qt.FramelessWindowHint)
main_window_tab.showMaximized()
tab1 = QtGui.QWidget()
tab2 = QtGui.QWidget()
tab3 = QtGui.QWidget()
tab4 = QtGui.QWidget()
tab5 = QtGui.QWidget()
tab6 = QtGui.QWidget()
tab7 = QtGui.QWidget()
admin_tab = QtGui.QWidget()
admin_tab_widget = AdminTabWidget()
admin_tab.setLayout(admin_tab_widget.get_admin_page_layout())
main_window_tab.addTab(admin_tab, "Admin")
main_window_tab.addTab(tab1, "tab1")
main_window_tab.addTab(tab2, "tab2")
main_window_tab.addTab(tab3, "tab3")
main_window_tab.addTab(tab4, "tab4")
main_window_tab.addTab(tab5, "tab5")
main_window_tab.addTab(tab6, "tab6")
main_window_tab.addTab(tab7, "tab7")
main_window_tab.show()
QtGui.QShortcut(QtGui.QKeySequence('Ctrl+Q'), main_window_tab, exit_application)
sys.exit(app.exec_())
The idea is to set the QStackedWidget with the Qt::AlignCenter alignment in the layout so it changes:
self.admin_page_layout.addWidget(self.admin_page_switch, 0, 0)
to:
self.admin_page_layout.addWidget(self.admin_page_switch, 0, 0, alignment=QtCore.Qt.AlignCenter)
I tried to create a 2D plot using QGraphicsItem, I was successful in doing that but when I drag the QGraphicsItem there is a delay and the view is distorted.
Searching for a solution, I came across this QGraphicsItem paint delay. I applied the mouseMoveEvent to my QGraphicsView but it did not resolve the problem.
Could someone tell me what is causing the problem and how can I fix it?
Here is my code:
from PyQt4 import QtGui, QtCore
import sys
import numpy as np
class MyGraphicsItem(QtGui.QGraphicsItem):
def __init__(self,dataX,dataY):
super(MyGraphicsItem,self).__init__()
self.Xval = dataX
self.Yval = dataY
self.Xvalmin = np.min(self.Xval)
self.Xvalmax = np.max(self.Xval)
self.Yvalmin = np.min(self.Yval)
self.Yvalmax = np.max(self.Yval)
self.rect = QtCore.QRectF(0,0,100,2)
self.points = []
self._picture = None
def paint(self, QPainter, QStyleOptionGraphicsItem, QWidget_widget=None):
if self._picture is None:
self._picture = QtGui.QPicture()
QPainter.begin(self._picture)
startPoint = QtCore.QPointF(0, 0)
cubicPath = QtGui.QPainterPath()
cubicPath.moveTo(startPoint)
for i in range(len(self.points) - 2):
points_ = self.points[i:i+3]
cubicPath.cubicTo(*points_)
QPainter.setPen(QtGui.QPen(QtCore.Qt.red))
QPainter.drawLine(0,10,100,10)
QPainter.drawLine(0,-10,0,10)
QPainter.setPen(QtGui.QPen(QtCore.Qt.black))
QPainter.drawPath(cubicPath)
QPainter.end()
else:
self._picture.play(QPainter)
def boundingRect(self):
return self.rect
class mygraphicsview(QtGui.QGraphicsView):
def __init__(self):
super(mygraphicsview,self).__init__()
def mouseMoveEvent(self, event):
QtGui.QGraphicsView.mouseMoveEvent(self,event)
if self.scene().selectedItems():
self.update()
class Mainwindow(QtGui.QMainWindow):
def __init__(self):
super(Mainwindow,self).__init__()
self.main_widget = QtGui.QWidget()
self.vl = QtGui.QVBoxLayout()
self.scene = QtGui.QGraphicsScene()
self.view = mygraphicsview()
self.Xval = np.linspace(0,100,1000)
self.Yval = np.sin(self.Xval)
self.painter = QtGui.QPainter()
self.style = QtGui.QStyleOptionGraphicsItem()
self.item = MyGraphicsItem(self.Xval, self.Yval)
self.item.paint(self.painter, self.style,self.main_widget)
self.item.setFlag(QtGui.QGraphicsItem.ItemIsMovable,True)
self.trans = QtGui.QTransform()
self.trans.scale(5,5)
self.item.setTransform(self.trans)
self.scene = QtGui.QGraphicsScene()
self.scene.addItem(self.item)
self.view.setScene(self.scene)
self.vl.addWidget(self.view)
self.main_widget.setLayout(self.vl)
self.setCentralWidget(self.main_widget)
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
window = Mainwindow()
window.show()
sys.exit(app.exec_())
I fixed the issue of dragging delay.
The reason for the occurrence of such a delay is due to the boundinRect() function. The boudingRect was too tight around the item designed.
Adding some marigin to the boundingRect(), solved the problem.
self.rect = QtCore.QRectF(-10,-10,120,25)
I need to adjust verticalScrollBar() on mouse wheel event. Trying to get the same behavior as horisontalScrollBar(). I mean it should remain in center of vertical scroll area.
Here is the code:
#!/usr/bin/env python
from PySide.QtGui import *
class windowClass(QWidget):
def __init__(self):
super(windowClass, self).__init__()
self.ly = QVBoxLayout(self)
self.view = viewClass()
self.ly.addWidget(self.view)
self.resize(500, 200)
class sceneClass(QGraphicsScene):
def __init__(self):
super(sceneClass, self).__init__()
self.setSceneRect(-1000, -1000, 2000, 2000)
self.grid = 30
class viewClass(QGraphicsView):
def __init__(self):
super(viewClass, self).__init__()
self.setDragMode(QGraphicsView.RubberBandDrag)
# self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
# self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
self.s = sceneClass()
self.setScene(self.s)
self.scaleY = 1
self.scaleX = 1
def wheelEvent(self, event):
self.setSceneScale(event.delta())
super(viewClass, self).wheelEvent(event)
def setSceneScale(self, delta):
if delta > 0:
self.scale(self.scaleX + 0.1, self.scaleY + 0.1)
else:
self.scale(self.scaleX - 0.1, self.scaleY - 0.1)
if __name__ == '__main__':
app = QApplication([])
w = windowClass()
w.show()
app.exec_()
As you can see I already used setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) but it did not worked because it just hides scroll bars
I've got the answer.
In constructor of QGraphicsView :
self.vscr = (self.size().height()/2)*-1
In wheelEvent :
self.verticalScrollBar().setValue(self.vscr)
I'm trying to draw vector segments on top of a QGraphicsPixmapItem, i used the mouse events to draw a first "red-dash-line" to positioning the segment. When the mouse is released the segment vertex are stored in a list wich is then appended to an other list. The metalist containing all the segments vertex is then drawn with a green-solid-line.
Once the user finished to draw segments i'm looking for a way to remove the segments from the scene and start over.
I'm not able to find a way to clean-up the scene removing the segments.
An ideal way will be to have each segment listed with a proper segment.identifier and then connect the "clear" push button to a self.scene.removeItem(segment.identifier) to remove it.
#!/usr/bin/env python
import sys
from PyQt4 import QtCore, QtGui
class MainWidget(QtGui.QWidget):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)
self.scene = QtGui.QGraphicsScene()
self.view = QtGui.QGraphicsView(self.scene)
layout = QtGui.QVBoxLayout()
layout.addWidget(self.view)
self.setLayout(layout)
self.bt = QtGui.QPushButton("Clear lines")
layout.addWidget(self.bt)
self.pixmap_item = QtGui.QGraphicsPixmapItem(QtGui.QPixmap('image.png'), None, self.scene)
self.pixmap_item.mousePressEvent = self.startLine
self.pixmap_item.mouseMoveEvent = self.mouseMoveEvent
self.pixmap_item.mouseReleaseEvent = self.updateProfile
self.startPoint = QtCore.QPointF()
self.profiles = []
self.bt.clicked.connect(self.clean)
self.pp = []
def clean(self):
#self.myItemGroup = self.scene.createItemGroup([])
self.myItemGroup.hide
print(dir(self.myItemGroup))
def startLine(self, event):
pen = QtGui.QPen(QtCore.Qt.red, 2, QtCore.Qt.DashDotLine)
self.sline = QtGui.QGraphicsLineItem(QtCore.QLineF(0,0,0,0))
self.sline.setPen(pen)
self.scene.addItem(self.sline)
print self.profiles
if (QtCore.Qt.LeftButton):
self.startPoint = QtCore.QPointF(event.pos())
def updateProfile(self, event):
self.profiles.append([self.startPoint.x(),self.startPoint.y(), event.pos().x(), event.pos().y()])
#print self.profiles
items = []
pen = QtGui.QPen(QtCore.Qt.green, 2, QtCore.Qt.SolidLine)
for i in self.profiles:
self.pline = QtGui.QGraphicsLineItem(QtCore.QLineF(i[0],i[1],i[2],i[3]))
self.pline.setPen(pen)
#self.scene.addItem(self.pline)
#self.pline.setGroup(self.myItemGroup)
items.append(self.pline)
self.myItemGroup = self.scene.createItemGroup(items)
self.lastPoint = self.startPoint
self.startPoint = QtCore.QPointF(self.profiles[-1][-2],self.profiles[-1][-1])
self.scene.removeItem(self.sline)
print self.startPoint, self.lastPoint
def mouseMoveEvent(self, event):
self.sline.setLine(self.startPoint.x(),self.startPoint.y(), event.pos().x(), event.pos().y())
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
widget = MainWidget()
widget.resize(640, 480)
widget.show()
sys.exit(app.exec_())