I am going to build a simple app using QTabWidet, I added tool bar inside it, but the problem is that when I add new tab, the toolbar show on that tab but when I go to the previous tab, the toolbar disappear. What is the problem kindly help me to solve this issue.
Code and Pictures given below.
from PySide2.QtWidgets import*
from PySide2.QtWebEngineWidgets import*
from PySide2.QtCore import QUrl,Qt
class mainwindow(QMainWindow):
def __init__(self):
super().__init__()
self.tabs = QTabWidget(self)
self.tabs.setDocumentMode(True)
self.tabs.tabBarDoubleClicked.connect(self.open_newTab)
action1 = QAction("tool1",self)
action2 = QAction("tool2",self)
action3 = QAction("tool3")
self.toolbar = QToolBar("title")
# v.addWidget(toolbar)
self.toolbar.addAction(action1)
# toolbar.setFixedHeight(30)
self.toolbar.addAction(action2)
self.toolbar.addAction(action3)
self.setCentralWidget(self.tabs)
self.add_new_tab()
self.toolbar.setStyleSheet("background:green;")
def add_new_tab(self,widget=None,label="Blank"):
w = QWidget()
v = QVBoxLayout()
v.addWidget(self.toolbar)
v.setContentsMargins(0,0,0,0)
v.setAlignment(Qt.AlignTop)
w.setLayout(v)
w.setStyleSheet("background:blue")
i = self.tabs.addTab(w,label)
self.tabs.setCurrentIndex(i)
def open_newTab(self,i):
if i==-1:
self.add_new_tab()
import sys
app = QApplication(sys.argv)
window = mainwindow()
window.show()
sys.exit(app.exec_())
As you can see in the above both pictures toolbar is present.
But when I go to the previous tab the toolbar disappear as shown in below image.
In my QMainWindow i have a button which opens a new QDialog in the bottom right monitorcorner with a successmessage when i click it.
Now, if i move the QMainWindow to another monitor (i have 3 monitor) and click the button the successmessage popup appears in the monitor where the QMainWindow was opened. What i want is that the popup message appears in the monitor where my QMainWindow actually is. So if i move the QMainWindow to Monitor 1 and click the button, the successpopup should opens in monitor 1. If the QMainWindow is in monitor 2, the successpopup should open in monitor 2 an same for monitor 3.
with
screenNumber = QDesktopWidget().screenNumber(self)
i can read the screennumber where the mainwindow is. and this works fine. Evertime i click the button i read out the screennumber. But i don't found a way, to set the screennumber to my notification.
Any ideas?
Edit:
maybe it helps if i show my notify class
notes.py
from UIs.UI_notify import Ui_Notification
from PyQt5.QtWidgets import QDialog, QApplication, QDesktopWidget
from PyQt5 import QtCore
from PyQt5.QtCore import QRect, QPropertyAnimation, QTimer
import sys
class icon():
checked = "check-circle"
alert = "times-circle"
question = "question-circle"
class notify(QDialog, Ui_Notification):
def __init__(self, parent=None):
super(notify,self).__init__(parent)
self.setupUi(self)
self.setWindowFlag(QtCore.Qt.WindowType.FramelessWindowHint)
self.setAttribute(QtCore.Qt.WidgetAttribute.WA_TranslucentBackground)
## Some helping stuff
############################################################
parent_sSize = QDesktopWidget().screenGeometry(parent)
parent_screenNumber = QDesktopWidget().screenNumber(parent)
sSize = QDesktopWidget().screenGeometry()
screenNumber = QDesktopWidget().screenNumber()
print("notification ScreenNumber = " + str(screenNumber))
print(sSize.width())
print(sSize.height())
print("Parents ScreenNumber = " + str(parent_screenNumber))
print(parent_sSize.width())
print(parent_sSize.height())
self.Note_Exit.clicked.connect(self.close)
## ScreenSize from parent
############################################################
self.hidedPos = QRect(parent_sSize.width()-self.width()-10,
parent_sSize.height()-self.height()+200,
self.frameGeometry().width(),
self.frameGeometry().height())
self.showPos = QRect(parent_sSize.width()-self.width()-10,
parent_sSize.height()-self.height()-50,
self.frameGeometry().width(),
self.frameGeometry().height())
def setNote(self, icon=icon.checked, headline="Headline", text="Text"):
self.icon = icon
self.headline = headline
self.text = text
self.noty_Label_Icon.setText(self.icon)
self.noty_Label_Headline.setText(self.headline)
self.noty_Label_Text.setText(self.text)
self.setGeometry(self.hidedPos)
self.anim = QPropertyAnimation(self,b"geometry")
self.anim.setDuration(700)
self.anim.setEasingCurve(QtCore.QEasingCurve.OutBack)
self.anim.setEndValue(self.showPos)
self.anim.start()
self.notyTimer = QTimer()
self.notyTimer.singleShot(4000,self.hideNote)
def hideNote(self):
self.anim = QPropertyAnimation(self,b"geometry")
self.anim.setDuration(700)
self.anim.setEasingCurve(QtCore.QEasingCurve.InOutBack)
self.anim.setEndValue(self.hidedPos)
self.anim.start()
self.anim.finished.connect(self.close)
if __name__ == "__main__":
notes = QApplication(sys.argv)
dialog = notify()
dialog.show()
sys.exit(notes.exec())
You cannot use the size of the widget during its construction, as at that moment it has a default size (640x480 for top level widgets, 100x30 for widgets created with a parent, including dialogs): the only reliable option is to use the sizeHint() or ensure that the layout has been properly activated with adjustSize().
Then, you don't need the screen to get the target position, as the parent geometry will suffice, but you do need it for the start position, otherwise the dialog will "pop up" at an arbitrary point below the window. Note that QDesktopWidget is considered obsolete, and you should use QScreen instead.
Finally, since you might want to reuse the notification, the start position should be set when the popup is actually being shown, not before. The same goes for the position when hiding (in case the notification could be moved).
class Notify(QDialog, Ui_Notification):
def __init__(self, parent):
super().__init__(parent)
self.setupUi(self)
self.setWindowFlag(QtCore.Qt.WindowType.FramelessWindowHint)
self.setAttribute(QtCore.Qt.WA_TranslucentBackground)
self.showAnim = QPropertyAnimation(self, b'geometry')
self.showAnim.setDuration(700)
self.showAnim.setEasingCurve(QtCore.QEasingCurve.OutBack)
self.hideAnim = QPropertyAnimation(self, b'geometry')
self.hideAnim.setDuration(700)
self.hideAnim.setEasingCurve(QtCore.QEasingCurve.InOutBack)
self.hideTimer = QTimer(self, singleShot=True)
self.hideTimer.setInterval(4000)
self.hideTimer.timeout.connect(self.hideNote)
self.showAnim.finished.connect(self.hideTimer.start)
self.hideAnim.finished.connect(self.close)
def setNote(self, icon=icon.checked, headline="Headline", text="Text"):
self.icon = icon
self.headline = headline
self.text = text
self.noty_Label_Icon.setText(self.icon)
self.noty_Label_Headline.setText(self.headline)
self.noty_Label_Text.setText(self.text)
self.adjustSize() # important!
endRect = self.rect()
center = self.parent().geometry().center()
endRect.moveCenter(center)
screen = QApplication.screenAt(center)
startRect = QRect(endRect)
startRect.moveTop(screen.geometry().bottom())
self.setGeometry(startRect)
self.showAnim.setStartValue(startRect)
self.showAnim.setEndValue(endRect)
self.showAnim.start()
self.show()
def hideNote(self):
rect = self.geometry()
self.hideAnim.setStartValue(rect)
screen = QApplication.screenAt(rect.center())
rect.moveTop(screen.geometry().bottom())
self.hideAnim.setEndValue(rect)
self.hideAnim.start()
if __name__ == "__main__":
notes = QApplication(sys.argv)
notes.setStyle('fusion')
w = QMainWindow()
b = QPushButton('click!')
w.setCentralWidget(b)
w.show()
notify = Notify(w)
b.clicked.connect(lambda: notify.setNote())
sys.exit(notes.exec())
Be aware that if you're going to create the popup every time, you should also set the WA_DeleteOnClose attribute in order to destroy it when closed, otherwise it will be kept in memory.
Note: QTimer.singleShot() is a static function, creating an instance of QTimer to use it is pointless, as that instance won't be used and a new QTimer would be created anyway.
Thank you.
In the meantime i found a solution which works for me.
Look a little dirty but works.
could you tell me, whats the difference between my code an yours?
Why should i use your code, except the fact that you are a better programmer ;-)
I set the WA_DeleteOnClose Attribute.
Good to know that. Thanks
notes.py
from UIs.UI_notify import Ui_Notification
from PyQt5.QtWidgets import QDialog, QApplication
from PyQt5 import QtCore
from PyQt5.QtCore import QRect, QPropertyAnimation, QTimer
import sys
class icon():
checked = "check-circle"
alert = "times-circle"
question = "question-circle"
clock = "clock"
class notify(QDialog, Ui_Notification):
def __init__(self, parent=None):
super(notify,self).__init__(parent)
self.setupUi(self)
self.setWindowFlag(QtCore.Qt.WindowType.FramelessWindowHint)
self.setAttribute(QtCore.Qt.WidgetAttribute.WA_TranslucentBackground)
self.setAttribute(QtCore.Qt.WidgetAttribute.WA_DeleteOnClose)
self.setWindowModality(QtCore.Qt.NonModal)
self.Note_Exit.clicked.connect(self.close)
self.parent_h = self.parent().geometry().height()
self.parent_w = self.parent().geometry().width()
self.parent_x = self.parent().geometry().x()
self.parent_y = self.parent().geometry().y()
self.dialog_w = self.width()
self.dialog_h = self.height()
self.setGeometry(self.parent_x+self.parent_w-self.dialog_w-10, self.parent_y+self.parent_h-self.dialog_h+120, self.dialog_w, self.dialog_h)
## ScreenSize from parent
############################################################
def setNote(self, icon=icon.checked, headline="Headline", text="Text"):
self.icon = icon
self.headline = headline
self.text = text
self.noty_Label_Icon.setText(self.icon)
self.noty_Label_Headline.setText(self.headline)
self.noty_Label_Text.setText(self.text)
self.anim = QPropertyAnimation(self,b"geometry")
self.anim.setDuration(700)
self.anim.setEasingCurve(QtCore.QEasingCurve.OutBack)
self.anim.setEndValue(QRect(self.parent_x+self.parent_w-self.dialog_w-10, self.parent_y+self.parent_h-self.dialog_h-20, self.dialog_w, self.dialog_h))
self.anim.start()
self.notyTimer = QTimer()
self.notyTimer.singleShot(4000,self.hideNote)
def hideNote(self):
self.anim = QPropertyAnimation(self,b"geometry")
self.anim.setDuration(700)
self.anim.setEasingCurve(QtCore.QEasingCurve.InOutBack)
self.anim.setEndValue(QRect(self.parent_x+self.parent_w-self.dialog_w-10, self.parent_y+self.parent_h-self.dialog_h+120, self.dialog_w, self.dialog_h))
self.anim.start()
self.anim.finished.connect(self.close)
if __name__ == "__main__":
notes = QApplication(sys.argv)
dialog = notify()
dialog.show()
sys.exit(notes.exec())
I made a QGraphicsTextItem and set plain text as its content. After that, I set the QGraphicsTextItem inside the QGraphicsWidget.
My question is, Is it possible to resize the QGraphicsTextItem including its text/contents like in this picture:
This is the video of the resizing that I'm asking for.
If this is possible, how can I apply it to the QGraphicsTextItem?
The first picture is the image of the QGraphicsTextItem but I have no idea how to implement the resizing in the video.
Things I've tried:
I tried using the setTextWidth() and setting it to 0.5 but it's not working.
I also tried using adjustSize() to the QGraphicsTextItem but it's also not working.
Code to reproduce the issue:
import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
class MainWindow(QMainWindow):
def __init__(self, *args, **kwargs):
super(MainWindow, self).__init__(*args, **kwargs)
self.view = QGraphicsView()
scene = QGraphicsScene()
#before resizing
item = QGraphicsTextItem("Line 1 Line 2 Line 3")
item.setFlags(QGraphicsWidget.ItemIsSelectable)
item.setPos(self.view.mapToScene(2, 2))
scene.addItem(item)
#after resizing
item_1 = QGraphicsTextItem("Line 1\nLine 2\nLine 3")
item_1.setFlags(QGraphicsWidget.ItemIsSelectable)
item_1.setPos(self.view.mapToScene(2, 30))
scene.addItem(item_1)
self.view.setScene(scene)
self.setCentralWidget(self.view)
if __name__ == '__main__':
app = QApplication(sys.argv)
w = MainWindow()
w.show()
app.exec_()
I have a Pyqt5 form where the user enters data. This data is sent to another module, where it is processed and returned for display in the form.
Very simplistically it looks like this:
frm.py
import sys
from PyQt5.QtWidgets import *
import mdl
def fnc0(in_val):
mdl.fnc1(in_val)
def fnc2(rezult):
msg.setText(rezult)
app = QApplication(sys.argv)
window = QWidget()
layout = QVBoxLayout()
btn = QPushButton('button')
btn.clicked.connect(lambda: fnc0(5))
layout.addWidget(btn)
msg = QLabel('')
layout.addWidget(msg)
window.setLayout(layout)
window.show()
sys.exit(app.exec_())
mdl.py
import frm
def fnc1(in_val):
out_val = str(in_val*2)
frm.fnc2(out_val)
However, when doing this, I get the error of using circular modules:
AttributeError: partially initialized module 'mdl' has no attribute 'fnc1' (most likely due to a circular import)
Is it possible to process the data sent from the form to another module, and then return the result to the form?
A possible solution is that in a third file we create a logic where we can register functions that receive the result and a function that invokes those functions:
core.py
_funct = []
def register_writer(func):
_funct.append(func)
return func
def write(text):
for f in _funct:
f(text)
mdl.py
import core
def fnc1(in_val):
out_val = str(in_val * 2)
core.write(out_val)
frm.py
import sys
from PyQt5.QtWidgets import *
import core
import mdl
#core.register_writer
def fnc2(rezult):
msg.setText(rezult)
app = QApplication(sys.argv)
window = QWidget()
layout = QVBoxLayout()
btn = QPushButton("button")
btn.clicked.connect(lambda: mdl.fnc1(5))
layout.addWidget(btn)
msg = QLabel()
layout.addWidget(msg)
window.setLayout(layout)
window.show()
sys.exit(app.exec_())
I got two py files. One has the main window with a QStackedWidget inside, the setCurrentWidget is set according to a condition. The other file has a widget which is dynamically added into the stacked widget and set as current widget when a button in the main window is clicked.
The widget in the second file has a dialog with a button in it. What I'm trying to do is, on clicking the button inside the dialog, the dialog should be closed and the setCurrentWidget is set according to the condition and the widget is removed from the stacked widget.
Here is what I've tried:
mainwindow.py
import sys
import os
import pathlib
from PySide2.QtWidgets import *
from PySide2 import *
from PySide2.QtCore import *
from PySide2.QtGui import *
list1 = ["item1", "item2", "item3"]
class MainWindow(QWidget):
def __init__(self):
super(MainWindow, self).__init__()
self.resize(400, 300)
self.toolbar = QWidget()
self.toolbar.setFixedHeight(30)
self.toolbar.setStyleSheet("background: grey;")
self.button = QPushButton("Click here!")
t_layout = QHBoxLayout()
t_layout.setMargin(0)
t_layout.addWidget(self.button)
self.toolbar.setLayout(t_layout)
self.p1_label = QLabel("Such empty!")
self.p1_label.setStyleSheet("font-size: 30px;")
self.p1_label.setAlignment(Qt.AlignCenter)
self.p2_widget = QWidget()
self.p2_widget.setStyleSheet("background: orange;")
self.sw = QStackedWidget()
self.sw.addWidget(self.p1_label)
self.sw.addWidget(self.p2_widget)
if not list1:
self.sw.setCurrentWidget(self.p1_label)
else:
self.sw.setCurrentWidget(self.p2_widget)
self.mw_layout = QVBoxLayout()
self.mw_layout.addWidget(self.toolbar)
self.mw_layout.addWidget(self.sw)
self.setLayout(self.mw_layout)
def switch_widget():
import widget_test
p3 = widget_test.widget()
self.sw.addWidget(p3)
self.sw.setCurrentWidget(p3)
self.button.clicked.connect(switch_widget)
def switch_back(self):
import widget_test
p3 = widget_test.widget()
mwin = MainWindow()
sw_ = mwin.sw
sw_.removeWidget(p3)
p1 = mwin.p1_label
p2 = mwin.p2_widget
if not list1:
sw_.setCurrentWidget(p1)
else:
sw_.setCurrentWidget(p2)
if __name__ == '__main__':
app = QApplication(sys.argv)
mw = MainWindow()
mw.show()
sys.exit(app.exec_())
widget.py
import sys
import os
import pathlib
import datetime
from PySide2.QtWidgets import *
from PySide2 import *
from PySide2.QtCore import *
from PySide2.QtGui import *
class widget(QWidget):
def __init__(self):
super(widget, self).__init__()
self.setStyleSheet("background: teal;")
widget_label = QLabel("fluid dynamics is cool")
show_pop_up = QPushButton("show pop up")
pop_up = QDialog(self)
pop_up_label = QLabel("click below to, hopefully, get outta here")
get_outta_here = QPushButton("get outta here")
pop_up_layout = QVBoxLayout()
pop_up_layout.addWidget(pop_up_label)
pop_up_layout.addWidget(get_outta_here)
pop_up.setLayout(pop_up_layout)
def show_popup():
pop_up.show()
def get_out():
from main_test import MainWindow
MainWindow.switch_back(self)
pop_up.reject()
get_outta_here.clicked.connect(get_out)
show_pop_up.clicked.connect(show_popup)
widget_layout = QVBoxLayout()
widget_layout.addWidget(widget_label)
widget_layout.addWidget(show_pop_up)
self.setLayout(widget_layout)
I could merge the code together and make it work but I'm trying to keep the directory clean.
There is a lot going on here, but let's break it down.
The main problem seems to be juggling between modules. Eventhough it might seem appealing to import the modules back and forth, it doesn't really work. What you need to look for, is the built-in Signals module that you can utilize.
Another bigger problem is that you are re-assigning some attributes eventhough you really shouldn't. You also should revisit the condition you are using to assign the .setCurrentWidget. Currently the condition reads as if list1 doesn't exist, do this. Else, do the other. Also, switch_widget should be outside of the def __init__(self):.
I rewrote some parts of the code to make it work with signals as an example for you.
mainwindow.py
import sys
import os
import pathlib
from PySide2.QtWidgets import *
from PySide2 import *
from PySide2.QtCore import *
from PySide2.QtGui import *
from widget_test import widget
list1 = ["item1", "item2", "item3"]
class MainWindow(QWidget):
def __init__(self):
super(MainWindow, self).__init__()
self.resize(400, 300)
self.toolbar = QWidget()
self.toolbar.setFixedHeight(30)
self.toolbar.setStyleSheet("background: grey;")
self.button = QPushButton("Click here!")
t_layout = QHBoxLayout()
t_layout.setMargin(0)
t_layout.addWidget(self.button)
self.toolbar.setLayout(t_layout)
self.p1_label = QLabel("Such empty!")
self.p1_label.setStyleSheet("font-size: 30px;")
self.p1_label.setAlignment(Qt.AlignCenter)
self.p2_widget = QWidget()
self.p2_widget.setStyleSheet("background: orange;")
self.p3 = None
self.sw = QStackedWidget()
self.sw.addWidget(self.p1_label)
self.sw.addWidget(self.p2_widget)
if not list1:
self.sw.setCurrentWidget(self.p1_label)
else:
self.sw.setCurrentWidget(self.p2_widget)
self.mw_layout = QVBoxLayout()
self.mw_layout.addWidget(self.toolbar)
self.mw_layout.addWidget(self.sw)
self.setLayout(self.mw_layout)
self.button.clicked.connect(self.switch_widget)
def switch_widget(self):
self.p3 = widget()
self.p3.update_signal.connect(self.switch_back)
self.sw.addWidget(self.p3)
self.sw.setCurrentWidget(self.p3)
def switch_back(self):
self.sw.removeWidget(self.p3)
if list1:
self.sw.setCurrentWidget(self.p1_label)
else:
self.sw.setCurrentWidget(self.p2_widget)
if __name__ == '__main__':
app = QApplication(sys.argv)
mw = MainWindow()
mw.show()
sys.exit(app.exec_())
widget.py
import sys
import os
import pathlib
import datetime
from PySide2.QtWidgets import *
from PySide2 import *
from PySide2.QtCore import *
from PySide2.QtGui import *
from PySide2.QtCore import Signal
class widget(QWidget):
update_signal = Signal()
def __init__(self):
super(widget, self).__init__()
self.setStyleSheet("background: teal;")
widget_label = QLabel("fluid dynamics is cool")
show_pop_up = QPushButton("show pop up")
pop_up = QDialog(self)
pop_up_label = QLabel("click below to, hopefully, get outta here")
get_outta_here = QPushButton("get outta here")
pop_up_layout = QVBoxLayout()
pop_up_layout.addWidget(pop_up_label)
pop_up_layout.addWidget(get_outta_here)
pop_up.setLayout(pop_up_layout)
def show_popup():
pop_up.show()
def get_out():
self.update_signal.emit()
pop_up.reject()
get_outta_here.clicked.connect(get_out)
show_pop_up.clicked.connect(show_popup)
widget_layout = QVBoxLayout()
widget_layout.addWidget(widget_label)
widget_layout.addWidget(show_pop_up)
self.setLayout(widget_layout)
Finally, check Python coding conventions for naming and other "minor" details.