Access A Variable from another class in PyQt5 - python

In PyQt5, I've wrote a GUI. Basically, when a button is pressed, it open a new window, where choose an item from a list. What I want is that after you close the new window, the item you chose appears as text on the first window. It's a hard to explain.
This is the code:
import sys
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QFont
from PyQt5 import QtWidgets
from PyQt5 import QtCore
from PyQt5 import QtGui
class Add(QtWidgets.QMainWindow):
def __init__(self):
super(Add, self).__init__()
#Set The UI
self.initUI()
#Set The GUI Position And Size
self.setGeometry(1050, 500, 400, 50)
#Set The GUI Title
self.setWindowTitle("Add")
def initUI(self):
Central = QtWidgets.QWidget(self)
self.setCentralWidget(Central)
self.deckButton = QtWidgets.QPushButton(self)
self.deckButton.setText("Choose")
self.deckButton.clicked.connect(self.open_deck_browser)
hbox = QtWidgets.QHBoxLayout()
hbox.addWidget(self.deckButton, 1)
Central.setLayout(hbox)
def open_deck_browser(self):
self.w = SetDeck()
self.w.show()
class SetDeck(QtWidgets.QMainWindow):
def __init__(self):
super(SetDeck, self).__init__()
#Set The UI
self.initUI()
#Set The GUI Position And Size
self.setGeometry(200, 200, 800, 640)
#Set The GUI Title
self.setWindowTitle("Choose Deck")
def initUI(self):
widAddToDeckWindow = QtWidgets.QWidget(self)
self.setCentralWidget(widAddToDeckWindow)
#Create The List Widget
self.deckList = QtWidgets.QListWidget()
self.deckList.insertItem(0, "Hello")
self.deckList.insertItem(1, "Hi")
self.deckList.insertItem(2, "Hello There")
self.deckList.item(0).setSelected(True)
self.deckList.itemSelectionChanged.connect(self.show_List)
print([x.row() for x in self.deckList.selectedIndexes()])
#Create The Select Deck Button
self.selectDeck = QtWidgets.QPushButton(self)
self.selectDeck.setText("Choose")
hboxCreateBottomButtons = QtWidgets.QHBoxLayout()
hboxCreateBottomButtons.addStretch()
hboxCreateBottomButtons.addWidget(self.selectDeck)
#Create The Main VBox
vboxMain = QtWidgets.QVBoxLayout()
vboxMain.addWidget(self.deckList)
vboxMain.addLayout(hboxCreateBottomButtons)
widAddToDeckWindow.setLayout(vboxMain)
def show_List(self):
print(repr(self.deckList.selectedItems()[0].text()))
def window():
app = QtWidgets.QApplication(sys.argv)
win = Add()
win.show()
sys.exit(app.exec_())
window()
I've tried using global variables, but it didn't work.

First of all, I recommend you improve your style when naming variables as they make reading easier, for example that the class name are nouns and not a verb.
Getting to the bottom of the problem, never use (or try to use) global variables as they cause silent bugs if there is a better option and you don't understand how it works. In the case that you want a window where you ask the user to provide information on how to select an option that will then be used in the main window then it is advisable to use a QDialog. In the following example, this is done and the "Choose" button is linked to the accept slot so that it closes the window, and that information can be used to know that the "x" button of the window was not closed. Also I have created a property that has the selected text.
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
class MainWindow(QtWidgets.QMainWindow):
def __init__(self):
super(MainWindow, self).__init__()
self.initUI()
self.setGeometry(1050, 500, 400, 50)
self.setWindowTitle("Add")
def initUI(self):
central = QtWidgets.QWidget(self)
self.setCentralWidget(central)
self.deckButton = QtWidgets.QPushButton()
self.deckButton.setText("Choose")
self.deckButton.clicked.connect(self.open_deck_browser)
box = QtWidgets.QVBoxLayout(central)
box.addWidget(self.deckButton)
self.label = QtWidgets.QLabel()
box.addWidget(self.label)
self.label.hide()
def open_deck_browser(self):
dialog = DeckDialog()
if dialog.exec_() == QtWidgets.QDialog.Accepted:
self.label.show()
self.label.setText(dialog.selected_text)
class DeckDialog(QtWidgets.QDialog):
def __init__(self):
super(DeckDialog, self).__init__()
self.initUI()
self.setGeometry(200, 200, 800, 640)
self.setWindowTitle("Choose Deck")
def initUI(self):
self.deckList = QtWidgets.QListWidget()
self.deckList.insertItem(0, "Hello")
self.deckList.insertItem(1, "Hi")
self.deckList.insertItem(2, "Hello There")
self.deckList.item(0).setSelected(True)
self.selectDeck = QtWidgets.QPushButton(self)
self.selectDeck.setText("Choose")
hboxCreateBottomButtons = QtWidgets.QHBoxLayout()
hboxCreateBottomButtons.addStretch()
hboxCreateBottomButtons.addWidget(self.selectDeck)
vboxMain = QtWidgets.QVBoxLayout(self)
vboxMain.addWidget(self.deckList)
vboxMain.addLayout(hboxCreateBottomButtons)
self.selectDeck.clicked.connect(self.accept)
#property
def selected_text(self):
items = self.deckList.selectedItems()
if items:
return items[0].text()
return ""
def main():
app = QtWidgets.QApplication(sys.argv)
win = MainWindow()
win.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main()

Related

Pushbutton is not being responsive

i'm pretty new to python and PyQt5.
My goal is to use a "Push Button" to move to the next widget in the "Stacked Layout". However, it's not being responsive, and it appears that it won't enter the function in order to move on to the next widget.
I have no idea wether its the inheritance i've messed up on, or something else. Any guidance is really appreciated. Thank you!
from PyQt5 import QtCore, QtGui, QtWidgets
class Menu(QtWidgets.QWidget):
def setupUI(self, Main):
Main.setObjectName("Main")
Main.setFixedSize(900, 500)
self.width = 900
self.height = 500
self.setFixedSize(self.width, self.height)
self.menu = QtWidgets.QStackedLayout()
self.welcomeMenu = QtWidgets.QWidget()
self.mainMenu = QtWidgets.QWidget()
self.welcomeUi()
self.menuUi()
self.menu.addWidget(self.welcomeMenu)
self.menu.addWidget(self.mainMenu)
def welcomeUi(self):
#Button for entering portal
self.entrBtn = QtWidgets.QPushButton(self.welcomeMenu)
self.entrBtn.setGeometry(QtCore.QRect(25,150,200,50))
self.entrBtn.setText("To the menu screen!")
#Having welcome text
self.welcomeText = QtWidgets.QLabel(self.welcomeMenu)
self.welcomeText.setGeometry(QtCore.QRect(30, 120, 480, 200))
self.welcomeText.setAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft|QtCore.Qt.AlignTop)
self.welcomeText.setText("Welcome!")
def menuUi(self):
self.text = QtWidgets.QLabel(self.mainMenu)
self.text.setGeometry(QtCore.QRect(30, 120, 480, 200))
self.text.setText("test")
class Main(QtWidgets.QMainWindow, Menu):
def __init__(self):
super(Main, self).__init__()
self.setupUI(self)
self.entrBtn.clicked.connect(self.menuWindow)
def menuWindow(self):
self.menu.setCurrentWidget(self.mainMenu)
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
m = Main()
sys.exit(app.exec_())
The problem is simple: QLabel is on top of the button so it will block all mouse events. The simple solution is to put QPushButton on QLabel using raise_():
# ...
self.welcomeText.setText("Welcome!")
self.entrBtn.raise_()
But that solves the superficial problem, you have other bigger problem: You should not inherit from 2 QWidget, also the Main is not shown. It is better to rewrite the code as follows:
from PyQt5 import QtCore, QtGui, QtWidgets
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super().__init__(parent)
self.welcomeMenu = QtWidgets.QWidget()
self.mainMenu = QtWidgets.QWidget()
self.fill_welcomeUi()
self.fill_menuUi()
self.stacked_lay = QtWidgets.QStackedLayout()
self.stacked_lay.addWidget(self.welcomeMenu)
self.stacked_lay.addWidget(self.mainMenu)
central_widget = QtWidgets.QWidget()
self.setCentralWidget(central_widget)
central_widget.setLayout(self.stacked_lay)
self.entrBtn.clicked.connect(self.menuWindow)
self.resize(640, 480)
def menuWindow(self):
self.stacked_lay.setCurrentWidget(self.mainMenu)
def fill_welcomeUi(self):
#Button for entering portal
self.entrBtn = QtWidgets.QPushButton(self.welcomeMenu)
self.entrBtn.setGeometry(QtCore.QRect(25,150,200,50))
self.entrBtn.setText("To the menu screen!")
#Having welcome text
self.welcomeText = QtWidgets.QLabel(self.welcomeMenu)
self.welcomeText.setGeometry(QtCore.QRect(30, 120, 480, 200))
self.welcomeText.setAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft|QtCore.Qt.AlignTop)
self.welcomeText.setText("Welcome!")
self.entrBtn.raise_()
def fill_menuUi(self):
self.text = QtWidgets.QLabel(self.mainMenu)
self.text.setGeometry(QtCore.QRect(30, 120, 480, 200))
self.text.setText("test")
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
m = MainWindow()
m.show()
sys.exit(app.exec_())

Use a variable/data in two tabs in PyQt5 / Python

I am trying to get input from a user in one tab then show it in the second tab. I could not find a question or an example about how to do that. This is an example of the code that I want to use, How can I show the data from Tab(1) Qlabel in QTextEdit box in Tab(2), I am a beginner in pyqt5 and not sure how this would work:
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
class TabWidget(QDialog):
def __init__(self):
super().__init__()
self.setWindowTitle('Tab Widget Application')
tabwidget = QTabWidget()
tabwidget.addTab(FirstTab(), 'First Tab')
tabwidget.addTab(SecondTab(),'Second Tab')
vbox=QVBoxLayout()
vbox.addWidget(tabwidget)
self.setLayout(vbox)
class FirstTab(QWidget):
def __init__(self):
super().__init__()
self.nameLabel = QLabel(self)
self.nameLabel.setText('Name:')
self.line = QLineEdit(self)
self.line.move(80, 20)
self.line.resize(200, 32)
self.nameLabel.move(20, 20)
self.btn=QPushButton('switch',self)
self.btn.move(80, 50)
self.btn.clicked.connect(lambda: SecondTab.display(SecondTab(),self.nameLabel.text()))
class SecondTab(QWidget):
def __init__(self):
super().__init__()
self.layout = QVBoxLayout()
self.editor=QTextEdit()
self.layout.addWidget(self.editor)
self.setLayout(self.layout)
def display(self,text):
self.editor.setText(text)
if __name__ == '__main__':
app=QApplication(sys.argv)
tabwidget = TabWidget()
tabwidget.resize(500,500)
tabwidget.show()
app.exec()
In order to track changes amongst child widgets, you'll need a main "controller".
Your QTabWidget will suffice, as long as you implement it in the correct way:
class TabWidget(QDialog):
def __init__(self):
super().__init__()
self.setWindowTitle('Tab Widget Application')
# if the target widget of the layout is provided as an init argument, the
# layout will be automatically set to it
vbox = QVBoxLayout(self)
tabwidget = QTabWidget()
vbox.addWidget(tabwidget)
firstTab = FirstTab()
tabwidget.addTab(firstTab, 'First Tab')
secondTab = SecondTab()
tabwidget.addTab(secondTab,'Second Tab')
firstTab.line.textChanged.connect(secondTab.editor.setPlainText)
firstTab.btn.clicked.connect(lambda: tabwidget.setCurrentWidget(secondTab))

PyQt: switch windows/layouts created by Qt Designer

I am creating an app using PyQt4. I have created two interfaces with Qt Designer. When a button is pushed I would like to switch between one layout and the other.
A sample of my code is:
from PyQt4 import QtGui, uic
form_class = uic.loadUiType("sample.ui")[0]
form_class2 = uic.loadUiType("sample2.ui")[0]
class SecondLayout(form_class2, QtGui.QMainWindow):
def __init__(self, parent=None):
QtGui.QMainWindow.__init__(self, parent)
form_class2.setupUi(self)
class MainWindow(form_class, QtGui.QMainWindow):
def __init__(self, parent=None):
QtGui.QMainWindow.__init__(self, parent)
self.setupUi(self)
self.btn.clicked.connect(self.open_new_window)
def open_new_window(self):
self.Window = SecondLayout()
# here I would like to switch the layout with a layout of self.Window
app = QtGui.QApplication(sys.argv)
myWindow = MainWindow(None)
myWindow.show()
app.exec_()
I have done a lot of searching and reading about QStackedLayout, but haven't been able to get it to work with layouts created in Qt Designer.
My Question is how would I be able to have one Main Window and switch its central widget but i'm not sure if that would work for the seperate menus. I have defined all the menus and widgets and status bars, etc. in Qt Designer as two different projects(both main windows) so I would like to have the main program in one of the main windows, then at some point create an instance of the second main window and switch the layout and all the widgets, menus, text edits, etc. I tried using setCentralWidget but hasn't worked for me.
Could someone please explain to me how to do this.
It sounds like you have two completely separate main windows. There is really no point in switching all the widgets, menus, toolbars, etc, because they will have no shared code. You might just as well simply hide one window, and then show the other one.
Here is a simple demo that shows one way to do that:
PyQt5
from PyQt5 import QtWidgets
class Window1(QtWidgets.QMainWindow):
def __init__(self, window2=None):
super(Window1, self).__init__()
self.setGeometry(500, 100, 100, 50)
self.button = QtWidgets.QPushButton('Go To Window 2', self)
self.button.clicked.connect(self.handleButton)
self.setCentralWidget(self.button)
self._window2 = window2
def handleButton(self):
self.hide()
if self._window2 is None:
self._window2 = Window2(self)
self._window2.show()
class Window2(QtWidgets.QMainWindow):
def __init__(self, window1=None):
super(Window2, self).__init__()
self.setGeometry(500, 100, 100, 50)
self.button = QtWidgets.QPushButton('Go To Window 1', self)
self.button.clicked.connect(self.handleButton)
self.setCentralWidget(self.button)
self._window1 = window1
def handleButton(self):
self.hide()
if self._window1 is None:
self._window1 = Window1(self)
self._window1.show()
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
window = Window1()
window.show()
sys.exit(app.exec_())
PyQt4
from PyQt4 import QtCore, QtGui
class Window1(QtGui.QMainWindow):
def __init__(self, window2=None):
super(Window1, self).__init__()
self.setGeometry(500, 100, 100, 50)
self.button = QtGui.QPushButton('Go To Window 2', self)
self.button.clicked.connect(self.handleButton)
self.setCentralWidget(self.button)
self._window2 = window2
def handleButton(self):
self.hide()
if self._window2 is None:
self._window2 = Window2(self)
self._window2.show()
class Window2(QtGui.QMainWindow):
def __init__(self, window1=None):
super(Window2, self).__init__()
self.setGeometry(500, 100, 100, 50)
self.button = QtGui.QPushButton('Go To Window 1', self)
self.button.clicked.connect(self.handleButton)
self.setCentralWidget(self.button)
self._window1 = window1
def handleButton(self):
self.hide()
if self._window1 is None:
self._window1 = Window1(self)
self._window1.show()
if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
window = Window1()
window.show()
sys.exit(app.exec_())

Add different text to a window

I have a button and a text label. Each time the button is pressed, i would like text placed from a line edit to be placed onto the window. So far I can only get one text to draw onto the window, even if I create another textlabel. Ive tried seeting a click count determining how many times a user has clicked a button but this doesnt work either. Heres what I have so far, any suggestions?
import sys
import os
from PyQt4 import QtCore, QtGui
from PyQt4.QtCore import *
from PyQt4.QtGui import *
from PyQt4.QtGui import QApplication
class Window(QMainWindow):
def __init__(self, *args):
QMainWindow.__init__(self, *args)
self.centralWidget = QWidget(self)
self.setCentralWidget(self.centralWidget)
self.setGeometry(450,100,350,680)
self.btn1 = QPushButton("Enter", self.centralWidget)
self.btn1.setGeometry(10,50,150, 20)
self.btn1.clicked.connect(self.enter)
self.edit = QtGui.QLineEdit(self)
self.edit.setGeometry(10, 10, 150, 20)
self.label = QtGui.QLabel(self)
self.label.setGeometry(240, 170,150, 20)
def enter(self):
self.label.setText(self.edit.text())
def main(args):
global app
app = App(args)
app.exec_()
class App(QApplication):
def __init__(self, *args):
QApplication.__init__(self, *args)
self.main = Window()
self.connect(self, SIGNAL("lastWindowClosed()"), self.byebye )
self.main.show()
def byebye( self ):
self.exit(0)
if __name__ == "__main__":
main(sys.argv)
There are a few problems with your example code, the main one being that you are trying to manually arrange the widgets, rather than using a layout.
It's hard to tell from your question exactly what you expect the output to be, so I've assumed you want the text from line-edit to be appended to the label, so that you end up with a series of lines.
Here's a simplified version of your example that hopefully does what you want:
from PyQt4 import QtCore, QtGui
class Window(QtGui.QMainWindow):
def __init__(self):
QtGui.QMainWindow.__init__(self)
self.btn1 = QtGui.QPushButton("Enter", self)
self.btn1.clicked.connect(self.enter)
self.edit = QtGui.QLineEdit(self)
self.label = QtGui.QLabel(self)
self.label.setAlignment(
QtCore.Qt.AlignTop | QtCore.Qt.AlignLeft)
widget = QtGui.QWidget(self)
layout = QtGui.QVBoxLayout(widget)
layout.addWidget(self.edit)
layout.addWidget(self.btn1)
layout.addWidget(self.label)
self.setCentralWidget(widget)
def enter(self):
text = self.edit.text()
if text:
self.label.setText('%s\n%s' % (self.label.text(), text))
if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
window = Window()
window.setGeometry(450, 100, 350, 680)
window.show()
sys.exit(app.exec_())

How to fit widgets within frame in python

I am pretty new at python but currently I am getting some problem here with the part where I am unable to get my stuff fit within the width of the window.
I am trying to set it in such a way that it is:
Eg. Name Button
by the way, I am using Maya to integrate and run my stuff.
If I set it to central, it fits but it is all over the place as I only wanted it to occupy a portion only. So are there any ways for me to fit it nicely into it?
By the way, if its possible, can it be done using my current codings?
from PyQt4.QtCore import *
from PyQt4.QtGui import *
import sip
import maya.OpenMayaUI as mui
import os
class MainWindow(QMainWindow):
def __init__(self, parent = None):
QMainWindow.__init__(self,parent)
self.resize(400,800)
self.setWindowTitle("GetShots")
self.pubDock = SetShotInfo()
self.pubDW = QDockWidget(self.tr(""), self)
self.pubDW.setWidget(self.pubDock)
# self.setCentralWidget(self.pubDW)
def getMayaWindow():
ptr = mui.MQtUtil.mainWindow()
return sip.wrapinstance(long(ptr), QObject)
def main():
global app
global form
app = qApp
form = MainWindow(getMayaWindow())
form.show()
class GetShot(QFrame):
def __init__(self, parent = None, display=None):
QFrame.__init__(self, parent)
self.createWidgets()
self.createLayout()
def createWidgets(self):
self.showLabel = QLabel('Show')
self.showName = QLineEdit()
self.showName.setText(str(os.environ['SHOW']))
self.shotLabel = QLabel('Shot Filter')
self.shotName = QLineEdit()
self.showButton = QPushButton('Set Show')
self.showButton.setMaximumWidth(200)
self.shotButton = QPushButton('Filter Shots')
self.shotButton.setMaximumWidth(200)
self.rootLabel = QLabel('Change Root')
self.rootButton = QComboBox()
def createLayout(self):
# Sets the Layout of Show and Shot
setShowLayout = QHBoxLayout()
setShowLayout.addWidget(self.showLabel)
setShowLayout.addWidget(self.showName)
setShowLayout.addWidget(self.showButton)
setShotLayout = QHBoxLayout()
setShotLayout.addWidget(self.shotLabel)
setShotLayout.addWidget(self.shotName)
setShotLayout.addWidget(self.shotButton)
# Sets the Change Root Layout
chgRootLayout = QHBoxLayout()
chgRootLayout.addWidget(self.rootLabel)
chgRootLayout.addWidget(self.rootButton)
mainLayout = QVBoxLayout()
mainLayout.addLayout(setShowLayout)
mainLayout.addLayout(setShotLayout)
mainLayout.addLayout(chgRootLayout)
self.setLayout(mainLayout)
if __name__ == '__main__':
main()
You need to use Layouts, combine vertical and horizontal and play with the size policy of the widgets to fit them as you need.
Here's a quick example:
import sys
from PyQt4 import QtCore, QtGui
class ButtonContainer(QtGui.QWidget):
def __init__(self):
super(ButtonContainer, self).__init__()
self.initUI()
def initUI(self):
self.setGeometry( 150, 150, 650, 350)
btn = QtGui.QPushButton('Name button', self)
btn.setSizePolicy( QtGui.QSizePolicy( QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Fixed ) )
vbox = QtGui.QVBoxLayout()
vbox.addWidget( btn )
self.setLayout(vbox)
self.show()
app = QtGui.QApplication(sys.argv)
ex = ButtonContainer()
sys.exit(app.exec_())
The commenters are right in suggesting QtDesigner, if you'd rather code it yourself at least have a mock up ui file where you can play interactively with the layouts and size policies, it's really helpful.

Categories

Resources