Using a button to open and close a matplotlib widget - python

The aim of what I've written so far is to have a "Temperature" button in my GUI that when pressed opens up a matplotlib plot that I made separately (mplwidget.py).
However, when I run the code, both the app and the widget open up simultaneously, and the Temperature button appears to have no function (even if I close the widget, pressing the button doesn't open it again).
import sys
from PyQt5.QtCore import QCoreApplication
from PyQt5.QtGui import QIcon
from PyQt5.QtWidgets import QApplication, QWidget, QMainWindow, QPushButton, QAction, QMessageBox
from PyQt5.uic.properties import QtGui
from mplwidget import animate #import animation widget
class window(QMainWindow):
def __init__(self):
super(window, self).__init__()
self.setGeometry(50, 50, 500, 300)
self.setWindowTitle('Temperature Control')
self.setWindowIcon(QIcon('adn.png'))
extractAction = QAction('&Quit', self)
extractAction.setShortcut('Ctrl+Q')
extractAction.setStatusTip('leave the app')
extractAction.triggered.connect(self.close_application)
self.statusBar()
mainMenu = self.menuBar()
fileMenu = mainMenu.addMenu('&File')
fileMenu.addAction(extractAction)
self.home()
def home(self):
btn = QPushButton('quit', self)
btn.clicked.connect(self.close_application)
btn.resize(btn.sizeHint())
btn.move(0, 100)
button = QPushButton('Temperature',self)
button.clicked.connect(self.opengraph)
button.move(50,200)
self.show()
def opengraph(self):
animate()
def close_application(self):
choice = QMessageBox.question(self, 'Message',
"Are you sure to quit?", QMessageBox.Yes |
QMessageBox.No, QMessageBox.No)
if choice == QMessageBox.Yes:
sys.exit()
else:
pass
if __name__ == "__main__":
def run():
app = QApplication(sys.argv)
Gui = window()
sys.exit(app.exec_())
run()
mplwidget is below
def GraphWidget():
fig = plt.figure()
ax1 = fig.add_subplot(1,1,1)
Time = []
Temp = []
def animate(i):
x = datetime.datetime.now()
y = numpy.random.randint(48,52)
Time.append(x)
Temp.append(int(y))
# print (Temp)
ax1.plot(Time,Temp)
ani = animation.FuncAnimation(fig,animate, interval=1000)
plt.show()

The problem is that plt.show() cannot start an event loop itself because the event loop is already running due to the QT window being open. In such cases one would need to call fig.show() instead, where fig is the figure in use.
This in turn leads to the problem that the function from the mplwidget.py module actually returns. Once it returns the reference for the animation is lost and will be garbage collected; hence no animation shows up on screen.
The solution is to let the function return the animation and store it somewhere in the main program.
import sys
from PyQt5.QtCore import QCoreApplication
from PyQt5.QtGui import QIcon
from PyQt5.QtWidgets import QApplication, QWidget, QMainWindow, QPushButton, QAction, QMessageBox
from PyQt5.uic.properties import QtGui
from mplwidget import showgraph
class window(QMainWindow):
def __init__(self):
super(window, self).__init__()
self.setGeometry(50, 50, 500, 300)
self.setWindowTitle('Temperature Control')
self.setWindowIcon(QIcon('adn.png'))
extractAction = QAction('&Quit', self)
extractAction.setShortcut('Ctrl+Q')
extractAction.setStatusTip('leave the app')
extractAction.triggered.connect(self.close_application)
self.statusBar()
mainMenu = self.menuBar()
fileMenu = mainMenu.addMenu('&File')
fileMenu.addAction(extractAction)
self.home()
def home(self):
btn = QPushButton('quit', self)
btn.clicked.connect(self.close_application)
btn.resize(btn.sizeHint())
btn.move(0, 100)
button = QPushButton('Temperature',self)
button.clicked.connect(self.opengraph)
button.move(50,200)
self.show()
def opengraph(self):
self.store = showgraph()
def close_application(self):
choice = QMessageBox.question(self, 'Message',
"Are you sure to quit?", QMessageBox.Yes |
QMessageBox.No, QMessageBox.No)
if choice == QMessageBox.Yes:
sys.exit()
else:
pass
if __name__ == "__main__":
def run():
app = QApplication(sys.argv)
Gui = window()
sys.exit(app.exec_())
run()
mplwidget.py:
import matplotlib.pyplot as plt
import datetime
import numpy
import matplotlib.animation as animation
def showgraph():
fig = plt.figure()
ax1 = fig.add_subplot(1,1,1)
Time = []
Temp = []
def animate(i):
x = datetime.datetime.now()
y = numpy.random.randint(48,52)
Time.append(x)
Temp.append(int(y))
ax1.plot(Time,Temp)
ani = animation.FuncAnimation(fig,animate, interval=1000)
fig.show()
return fig, ani

Try it:
import sys
from PyQt5.QtGui import QIcon
from PyQt5.QtWidgets import QApplication, QMainWindow, QPushButton, QAction, QMessageBox
from mplwidget import MplWindow # +++
class window(QMainWindow):
def __init__(self):
super(window, self).__init__()
self.setGeometry(50, 50, 500, 300)
self.setWindowTitle('Temperature Control')
self.setWindowIcon(QIcon('adn.png'))
extractAction = QAction('&Quit', self)
extractAction.setShortcut('Ctrl+Q')
extractAction.setStatusTip('leave the app')
extractAction.triggered.connect(self.close_application)
self.statusBar()
mainMenu = self.menuBar()
fileMenu = mainMenu.addMenu('&File')
fileMenu.addAction(extractAction)
self.matplWindow = MplWindow() # +++
self.home()
def home(self):
btn = QPushButton('quit', self)
btn.clicked.connect(self.close_application)
btn.resize(btn.sizeHint())
btn.move(0, 100)
button = QPushButton('Temperature',self)
button.clicked.connect(self.opengraph)
button.move(50,200)
self.show()
def opengraph(self):
self.matplWindow.funAnimation() # +++
def close_application(self):
choice = QMessageBox.question(self, 'Message',
"Are you sure to quit?", QMessageBox.Yes |
QMessageBox.No, QMessageBox.No)
if choice == QMessageBox.Yes:
sys.exit()
else:
pass
if __name__ == "__main__":
app = QApplication(sys.argv)
Gui = window()
sys.exit(app.exec_())
mplwidget.py
import matplotlib.pyplot as plt
import numpy
import datetime
import matplotlib.animation as animation
from PyQt5.QtWidgets import QDialog, QApplication, QPushButton, QVBoxLayout
class MplWindow(QDialog):
Time = []
Temp = []
def __init__(self, parent=None):
super(MplWindow, self).__init__(parent)
def funAnimation(self):
self.fig = plt.figure()
self.ax1 = self.fig.add_subplot(1,1,1)
self.ani = animation.FuncAnimation(self.fig, self.animate, interval=1000)
plt.show()
def animate(self, i):
x = datetime.datetime.now()
y = numpy.random.randint(48,52)
self.Time.append(x)
self.Temp.append(int(y))
self.ax1.plot(self.Time, self.Temp)

Related

pyqt5 : Build an overlay that updates under specific conditions on top of an existing program

(pyqt5 noob here.)
I want to create an overlay that change text location when some conditions are met. I run it under a thread, that I can control from main, as this would be used as an extension of an already existing program. This one would provide coordinates, and the overlay should update the text location based on those.
However, this error is triggered :
A QApplication::exec: Must be called from the main thread is called
I don't get what I'm missing here.
(I've noticed that using X11BypassWindowManagerHint causes some issues, especially with event triggers, but I want the overlay to be transparent, always displayed above the window I'm using, and clickable-through).
Any help, advice or suggestions would be much appreciated !
import sys
from PyQt5.QtWidgets import QApplication, QLabel, QMainWindow, QVBoxLayout, QWidget, QDesktopWidget
from PyQt5.QtGui import QFont
from PyQt5.QtCore import Qt, QCoreApplication, QThread, pyqtSignal, pyqtSlot
from time import sleep
class text_thread(QThread):
position_changed = pyqtSignal(int, int)
def __init__(self, app):
self.app = app
QThread.__init__(self)
def run(self):
self.window = QMainWindow()
self.window.setWindowFlag(Qt.X11BypassWindowManagerHint)
self.window.setWindowFlag(Qt.FramelessWindowHint)
self.window.setWindowFlag(Qt.WindowStaysOnTopHint)
self.window.setAttribute(Qt.WA_TranslucentBackground)
self.window.resize(500, 500)
self.f = QFont("Arial", 30, QFont.Bold)
self.label = QLabel("Text")
self.label.setFont(self.f)
self.label.setGeometry(100, 100, 50, 50)
self.layout = QVBoxLayout()
self.layout.addWidget(self.label)
self.central_widget = QWidget()
self.central_widget.setLayout(self.layout)
self.window.setCentralWidget(self.central_widget)
self.position_changed.connect(self.update_position)
self.window.show()
self.app.exec()
#pyqtSlot(int, int)
def update_position(self, x, y):
self.label.setGeometry(x, y, 50, 50)
app = QApplication(sys.argv)
thread = text_thread(app)
thread.start()
while True:
for i in range(10):
thread.position_changed.emit(100+i*10, 100+i*10)
sleep(1)
I believe that this way you can get a result similar to what you want.
I recommend isolating your test tool.
import sys
from PyQt5.QtWidgets import QApplication, QLabel, QMainWindow, QVBoxLayout, QWidget, QDesktopWidget
from PyQt5.QtGui import QFont
from PyQt5.QtCore import pyqtSignal as Signal, QObject, Qt, QCoreApplication, QThread, pyqtSignal, pyqtSlot
import time
class Tester(QObject):
sig_positions = Signal(int, int)
#pyqtSlot(int)
def action(self, n):
for i in range(1, n+1):
time.sleep(1)
self.sig_positions.emit(100+i*10, 100+i*10)
class Window(QMainWindow):
sig_requested = Signal(int)
def __init__(self):
super().__init__()
self.setWindowFlag(Qt.X11BypassWindowManagerHint)
self.setWindowFlag(Qt.FramelessWindowHint)
self.setWindowFlag(Qt.WindowStaysOnTopHint)
self.setAttribute(Qt.WA_TranslucentBackground)
self.resize(500, 500)
self.f = QFont("Arial", 30, QFont.Bold)
self.label = QLabel("Text")
self.label.setFont(self.f)
self.label.setGeometry(100, 100, 50, 50)
self.layout = QVBoxLayout()
self.layout.addWidget(self.label)
self.central_widget = QWidget()
self.central_widget.setLayout(self.layout)
self.setCentralWidget(self.central_widget)
self.t = Tester()
self.q = QThread()
self.t.sig_positions.connect(self.update_position)
self.sig_requested.connect(self.t.action)
self.t.moveToThread(self.q)
self.q.start()
self.show()
def start_test(self):
print('start')
self.sig_requested.emit(3)
def update_position(self, x, y):
print('update_position')
self.label.setGeometry(x, y, 50, 50)
if __name__ == "__main__":
App = QApplication(sys.argv)
window = Window()
window.start_test()
sys.exit(App.exec())

pyqt5 and vtk object integration

i would like to embed the glb file to pyqt gui with vtk python library. I wrote pieces of code but it does not embed the sketch to the pyqt gui. Everytime there have been placing in the second windows form. Here is the example:
And here is the my source code that i am trying to embed it to gui:
import sys
import vtk
try:
from PyQt5.QtWidgets import QMainWindow, QAction, qApp, QApplication
from PyQt5.QtWidgets import QWidget, QSizePolicy, QPushButton, QVBoxLayout, QFrame
from PyQt5.QtGui import QIcon
from PyQt5.QtCore import Qt, pyqtSignal, QTimer, QObject, QSize, QEvent
except ImportError:
raise ImportError("Cannot load either PyQt5")
from vtk.qt.QVTKRenderWindowInteractor import QVTKRenderWindowInteractor
class Menu(QMainWindow):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
importer = vtk.vtkGLTFImporter()
importer.SetFileName("uydu.glb")
importer.Read()
global vtk_render_window
vtk_renderer = importer.GetRenderer()
vtk_render_window = importer.GetRenderWindow()
self.setGeometry(190, 300, 300, 200)
self.setWindowTitle('Simple menu')
self.show()
self.frame = QFrame()
self.vl = QVBoxLayout()
vtk_render_window_interactor = QVTKRenderWindowInteractor(self.frame)
vtk_render_window_interactor.SetRenderWindow(vtk_render_window)
colors = vtk.vtkNamedColors()
vtk_renderer.SetBackground(colors.GetColor3d('White'))
actor = vtk.vtkActor()
actor.GetProperty().SetDiffuse(0.8)
actor.GetProperty().SetDiffuseColor(colors.GetColor3d('Black'))
actor.GetProperty().SetSpecular(0.3)
actor.GetProperty().SetSpecularPower(60.0)
vtk_render_window.SetSize(600, 600)
vtk_render_window.SetWindowName('3D Visualizer')
vtk_render_window_interactor.Initialize()
# Add callback for getting data from Arduino
#vtk_render_window_interactor.CreateRepeatingTimer(1000)
#vtk_render_window_interactor.AddObserver("TimerEvent", information_callback)
global vtk_actors
vtk_actors = vtk_renderer.GetActors
self.vl.addWidget(vtk_render_window_interactor)
self.renderer = vtk.vtkRenderer()
self.renderer.SetBackground(.3, .4, .5 )
self.renwin = vtk_render_window_interactor.GetRenderWindow()
self.renwin.AddRenderer(self.renderer)
# An interactor
self.inter = self.renwin.GetInteractor()
# add the custom style
self.style = MouseInteractorHighLightActor()
self.style.SetDefaultRenderer(self.renderer)
vtk_render_window_interactor.GetRenderWindow().AddRenderer(self.renderer)
#self.iren = self.vtkWidget.GetRenderWindow().GetInteractor()
self.inter.SetInteractorStyle(self.style)
#self.iren.SetInteractorStyle(self.inter)
#self.iren = self.vtkWidget.GetRenderWindow().SetInteractor(self.inter)
self.renderer.ResetCamera()
self.frame.setLayout(self.vl)
self.setCentralWidget(self.frame)
self.show()
self.inter.Initialize()
self.inter.Start()
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = Menu()
sys.exit(app.exec_())
You have to pass the renderWindow of vtkGLTFImporter as rw parameter to the QVTKRenderWindowInteractor widget:
import sys
import vtk
try:
from PyQt5.QtWidgets import QMainWindow, QApplication
from PyQt5.QtWidgets import QWidget, QVBoxLayout
except ImportError:
raise ImportError("Cannot load either PyQt5")
from vtk.qt.QVTKRenderWindowInteractor import QVTKRenderWindowInteractor
class Menu(QMainWindow):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.setGeometry(190, 300, 300, 200)
self.setWindowTitle("Simple menu")
self.container = QWidget()
vl = QVBoxLayout(self.container)
self.setCentralWidget(self.container)
self.resize(640, 480)
importer = vtk.vtkGLTFImporter()
importer.SetFileName("uydu.glb")
importer.Read()
renderer = importer.GetRenderer()
render_window = importer.GetRenderWindow()
vtk_widget = QVTKRenderWindowInteractor(rw=render_window)
vl.addWidget(vtk_widget)
vtk_widget.Initialize()
vtk_widget.Start()
colors = vtk.vtkNamedColors()
renderer.SetBackground(colors.GetColor3d("White"))
renderer.ResetCamera()
if __name__ == "__main__":
app = QApplication(sys.argv)
ex = Menu()
ex.show()
sys.exit(app.exec_())

How to show new QMainWindow in every loop in PyQT5?

I'm trying to write a Python program using PyQt5 that will display a window in each iteration of the for loop. I would like to close after incrementing and displaying the next window. However, I do not know how to stop the loop every iteration and at the moment I am getting 6 windows at once.
main.py
import sys
from PyQt5.QtWidgets import (QLineEdit, QVBoxLayout, QMainWindow,
QWidget, QDesktopWidget, QApplication, QPushButton, QLabel,
QComboBox, QFileDialog, QRadioButton)
from PyQt5.QtCore import pyqtSlot, QByteArray
from alert import Window2
from test import test
class SG(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.resize(300, 150)
self.setWindowTitle('TEST')
self.resultsGen = QPushButton('TEST', self)
self.resultsGen.clicked.connect(lambda: self.on_click())
self.show()
#pyqtSlot()
def on_click(self):
test(self)
if __name__ == '__main__':
app = QApplication(sys.argv)
sg = SG()
sys.exit(app.exec_())
alert.py
from PyQt5.QtWidgets import (QLineEdit, QVBoxLayout, QMainWindow,
QWidget, QDesktopWidget, QApplication, QPushButton, QLabel,
QComboBox, QFileDialog, QRadioButton)
from PyQt5.QtCore import pyqtSlot, QByteArray
from PyQt5.QtGui import QPixmap
from PyQt5 import QtGui, QtCore
class Window2(QMainWindow):
def __init__(self):
super().__init__()
self.initPopup()
def initPopup(self):
self.resize(500, 500)
self.setWindowTitle("Window22222")
self.central_widget = QWidget()
self.setCentralWidget(self.central_widget)
lay = QVBoxLayout(self.central_widget)
label = QLabel(self)
pixmap = QPixmap('cropped/8.png')
label.setPixmap(pixmap)
self.resize(pixmap.width(), pixmap.height())
lay.addWidget(label)
self.textbox = QLineEdit(self)
self.textbox.move(20, 20)
self.textbox.resize(280, 40)
# Create a button in the window
self.button = QPushButton('Show text', self)
self.button.move(20, 80)
# connect button to function on_click
self.button.clicked.connect(lambda: self.on_clickX())
self.show()
#pyqtSlot()
def on_clickX(self):
textboxValue = self.textbox.text()
print(textboxValue)
self.textbox.setText("")
self.hide()
test.py
from alert import Window2
def test(self):
for x in range(6):
w = Window2()
As soon as you run the for cycle, all the code of the initialization will be executed, which includes the show() call you used at the end of initPopup().
A simple solution is to create a new signal that is emitted whenever you hide a window, and connect that signal to a function that creates a new one until it reaches the maximum number.
main.py:
import sys
from PyQt5.QtWidgets import QWidget, QApplication, QPushButton
from alert import Window2
class SG(QWidget):
def __init__(self):
super().__init__()
self.initUI()
self.alerts = []
def initUI(self):
self.resize(300, 150)
self.setWindowTitle('TEST')
self.resultsGen = QPushButton('TEST', self)
self.resultsGen.clicked.connect(self.nextAlert)
self.show()
def nextAlert(self):
if len(self.alerts) >= 6:
return
alert = Window2()
self.alerts.append(alert)
alert.setWindowTitle('Window {}'.format(len(self.alerts)))
alert.closed.connect(self.nextAlert)
alert.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
sg = SG()
sys.exit(app.exec_())
alert.py:
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
class Window2(QMainWindow):
closed = pyqtSignal()
def __init__(self):
super().__init__()
self.initPopup()
def initPopup(self):
self.resize(500, 500)
self.central_widget = QWidget()
self.setCentralWidget(self.central_widget)
lay = QVBoxLayout(self.central_widget)
label = QLabel(self)
pixmap = QPixmap('cropped/8.png')
label.setPixmap(pixmap)
self.resize(pixmap.width(), pixmap.height())
lay.addWidget(label)
self.textbox = QLineEdit(self)
lay.addWidget(self.textbox)
# Create a button in the window
self.button = QPushButton('Show text', self)
lay.addWidget(self.button)
# connect button to function on_click
self.button.clicked.connect(lambda: self.on_clickX())
self.show()
#pyqtSlot()
def on_clickX(self):
textboxValue = self.textbox.text()
print(textboxValue)
self.textbox.setText("")
self.hide()
self.closed.emit()
Just note that with this very simplified example the user might click on the button of the "SG" widget even if an "alert" window is visibile. You might prefer to use a QDialog instead of a QMainWindow and make the main widget a parent of that dialog.
main.py:
class SG(QWidget):
# ...
def nextAlert(self):
if len(self.alerts) >= 6:
return
alert = Window2(self)
# ...
alert.py:
class Window2(QDialog):
closed = pyqtSignal()
def __init__(self, parent):
super().__init__()
self.initPopup()
def initPopup(self):
self.resize(500, 500)
# a QDialog doesn't need a central widget
lay = QVBoxLayout(self)
# ...
Also, if an alert window is closed using the "X" button the new one will not be shown automatically. To avoid that, you can implement the "closeEvent" and ignore the event, so that the user will not be able to close the window until the button is clicked. As QDialogs can close themself when pressing the escape key, I'm also ignoring that situation.
alert.py:
class Window2(QMainWindow):
# ...
def closeEvent(self, event):
event.ignore()
def keyPressEvent(self, event):
if event.key() != Qt.Key_Escape:
super().keyPressEvent(event)

Button is not working on the second window of pyqt5

I'm making a first come first served scheduler using pyqt5.
I have the main window which includes textbox asking the user for scheduler type, when button "GO" is clicked, the second window is opened which asks the user for more information about the scheduler like process numbers and burst time .
When button "GO" on the second window is clicked, a Gantt chart should appear after processing the information.
The problem is that the button on the second window is not working at all.
I have found a similar question, but I didn't quite got the solution, plus I'm not using JSON.
Code:
import sys
from PyQt5 import QtGui
from PyQt5.QtWidgets import QMainWindow,QApplication, QComboBox, QDialog,QDialogButtonBox, QFormLayout, QGridLayout, QGroupBox, QHBoxLayout,QLabel, QLineEdit, QMenu, QMenuBar, QPushButton, QSpinBox, QTextEdit,QVBoxLayoutQSpinBox, QTextEdit, QVBoxLayout
from PyQt5.QtGui import QIcon
from PyQt5.QtCore import pyqtSlot
import matplotlib.pyplot as plt
import numpy as np
import linked_list
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("My Program")
self.setWindowIcon(QtGui.QIcon("download.jpg"))
self.setGeometry(50,50,500,300)
self.home()
self.show()
def home(self):
self.label2=QLabel(self)
self.label2.setText("Type of Scheduler")
self.label2.move(10,50)
self.textbox2=QLineEdit(self)
self.textbox2.move(100,50)
self.button=QPushButton("Go",self)
self.button.move(0,200)
self.button.clicked.connect(self.runcode)
def runcode(self):
schedular_type=self.textbox2.text()
if(schedular_type=="FCFS"):
self.close()
self.fcfs=Window2(self)
Self.fcfs.__init__()
class Window2(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("My Program")
self.setWindowIcon(QtGui.QIcon("download.jpg"))
self.setGeometry(50,50,500,300)
self.home()
self.show()
def home(self):
self.label1=QLabel(self)
self.label1.setText("No of Processes")
self.label1.move(10,0) #col ,row
self.textbox=QLineEdit(self)
self.textbox.move(100,0)
self.label3=QLabel(self)
self.label3.setText("Processess Names")
self.label3.move(10,100)
self.label4=QLabel(self)
self.label4.setText("Burst Time")
self.label4.move(120,100)
self.label5=QLabel(self)
self.label5.setText("Arrival Time")
self.label5.move(200,100)
self.names=QLineEdit(self)
self.names.move(10,150)
# self.names.resize(100,160)
self.burst=QLineEdit(self)
self.burst.move(120,150)
#self.burst.resize(100,160)
self.arrival=QLineEdit(self)
self.arrival.move(250 ,150)
#self.arrival.resize(100,160)
#self.textEdit=QTextEdit(self)
#self.textEdit.move(20,250)
self.button=QPushButton("Go",self)
self.button.move(0,200)
self.button.clicked.connect(self.fcfs)
def fcfs(self):
//
def main():
app = QApplication(sys.argv)
main = MainWindow()
main.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
Set a parent to second window, also you are calling ____init____ method of Window2 twice.
Here is the fixed code :
import sys
from PyQt5 import QtGui
from PyQt5.QtWidgets import (QMainWindow, QApplication, QComboBox,
QDialog, QDialogButtonBox, QFormLayout, QGridLayout, QGroupBox,
QHBoxLayout, QLabel, QLineEdit, QMenu, QMenuBar, QPushButton, QSpinBox,
QTextEdit, QVBoxLayout)
from PyQt5.QtGui import QIcon
from PyQt5.QtCore import pyqtSlot
import matplotlib.pyplot as plt
import numpy as np
import linked_list
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("My Program")
self.setWindowIcon(QtGui.QIcon("download.jpg"))
self.setGeometry(50, 50, 500, 300)
self.home()
self.show()
def home(self):
self.label2 = QLabel(self)
self.label2.setText("Type of Scheduler")
self.label2.move(10, 50)
self.textbox2 = QLineEdit(self)
self.textbox2.move(100, 50)
self.button = QPushButton("Go", self)
self.button.move(0, 200)
self.button.clicked.connect(self.runcode)
def runcode(self):
schedular_type = self.textbox2.text()
if(schedular_type == "FCFS"):
self.close()
fcfs = Window2(self)
# Do not call __init__ explicitly below
# fcfs.__init__()
class Window2(QMainWindow):
def __init__(self,parent=None):
super().__init__(parent)
# always try to set a parent
self.setWindowTitle("My Program")
self.setWindowIcon(QtGui.QIcon("download.jpg"))
self.setGeometry(50, 50, 500, 300)
self.home()
self.show()
def home(self):
self.label1 = QLabel(self)
self.label1.setText("No of Processes")
self.label1.move(10, 0) # col ,row
self.textbox = QLineEdit(self)
self.textbox.move(100, 0)
self.label3 = QLabel(self)
self.label3.setText("Processess Names")
self.label3.move(10, 100)
self.label4 = QLabel(self)
self.label4.setText("Burst Time")
self.label4.move(120, 100)
self.label5 = QLabel(self)
self.label5.setText("Arrival Time")
self.label5.move(200, 100)
self.names = QLineEdit(self)
self.names.move(10, 150)
# self.names.resize(100,160)
self.burst = QLineEdit(self)
self.burst.move(120, 150)
# self.burst.resize(100,160)
self.arrival = QLineEdit(self)
self.arrival.move(250, 150)
# self.arrival.resize(100,160)
# self.textEdit=QTextEdit(self)
# self.textEdit.move(20,250)
self.button = QPushButton("Go", self)
self.button.move(0, 200)
self.button.clicked.connect(self.fcfs)
def fcfs(self):
no_of_process = self.textbox.text()
process_names = self.names.text()
burst_time = self.burst.text()
arrival_time = self.arrival.text()
names_list = process_names.split()
burst_list = burst_time.split()
arrival_list = arrival_time.split()
# integer conversion
burst_list = [int(i) for i in burst_list]
arrival_list = [int(i) for i in arrival_list]
no_of_process = int(no_of_process)
ls = LinkedList()
i = 0
while i < no_of_process:
ls.append(names_list[i], burst_list[i], arrival_list[i])
i = i + 1
time = arrival_list[0]
j = 0
start = []
end = []
name = []
while j < (ls.size()):
while(time < arrival_list[j]):
time = time + 1
start.append(time)
time = time + burst_list[j]
end.append(time)
name.append(names_list[j])
j = j + 1
waiting_time = 0
k = 0
average_waiting = 0
while k < (ls.size()):
waiting_time = waiting_time + \
end[k] - arrival_list[k] - burst_list[k]
average_waiting = waiting_time / ls.size()
k = k + 1
x = name
begin = np.array(start)
end = np.array(end)
plt.barh(range(len(begin)), end - begin, left=begin)
plt.yticks(range(len(begin)), x)
#plt.text(0.6,1.5,('average waiting is ',average_waiting))
plt.annotate(("average waiting is", average_waiting), xy=(0.5, 1.49))
plt.show()
def main():
app = QApplication(sys.argv)
main = MainWindow()
main.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
the crucial part is:
def __init__(self,parent=None):
super().__init__(parent)

PyQt4 using global variable from function in class

I understand that to use a global variable from a function, you Need to execute the function first:
def f():
global s
s = 'Hello'
f()
print(s)
But how do I use variable s globally in following example:
import sys
from PyQt4.QtGui import QApplication, QMainWindow, QPushButton, QLineEdit, QLabel, QComboBox, QProgressBar, QFileDialog
from PyQt4.QtCore import QSize, pyqtSlot
class App(QMainWindow):
def __init__(self):
super(App, self).__init__()
self.setGeometry(500, 300, 820, 350)
self.setWindowTitle("Widget")
self.initUI()
def initUI(self):
#Buttons
btnposx = 30
btnposy = 50
self.btn4 = QPushButton('GetValue', self)
self.btn4.move(btnposx,btnposy+220)
self.btn4.clicked.connect(self.cb_get)
self.cb = QComboBox(self)
self.cb.move(btnposx+120,btnposy+150)
self.cb.resize(80,22)
self.cb.setMaximumSize(QSize(80,1000000))
self.cb.addItem('A')
self.cb.addItem('B')
self.cb.addItem('C')
self.cb.addItem('D')
self.cb.addItem('E')
self.show()
#pyqtSlot()
def cb_get(self):
global s
cbtext = str(self.cb.currentText())
s = cbtext
print(s)
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = App()
sys.exit(app.exec_())
This code shows a PyQt4 Widget. Function cb_get acquires the Value of a QcomboBox and can be used within the class App(). The Value is saved to variable s. How do I use variable s globally?
The only way I seem to get it to work is to write a new function for s and execute it on button click:
import sys
from PyQt4.QtGui import QApplication, QMainWindow, QPushButton, QLineEdit, QLabel, QComboBox, QProgressBar, QFileDialog
from PyQt4.QtCore import QSize, pyqtSlot
class App(QMainWindow):
def __init__(self):
super(App, self).__init__()
self.setGeometry(500, 300, 820, 350)
self.setWindowTitle("Widget")
self.initUI()
def initUI(self):
#Buttons
btnposx = 30
btnposy = 50
self.btn4 = QPushButton('GetValue', self)
self.btn4.move(btnposx,btnposy+220)
self.btn4.clicked.connect(self.cb_get)
self.btn4.clicked.connect(self.p)
self.cb = QComboBox(self)
self.cb.move(btnposx+120,btnposy+150)
self.cb.resize(80,22)
self.cb.setMaximumSize(QSize(80,1000000))
self.cb.addItem('A')
self.cb.addItem('B')
self.cb.addItem('C')
self.cb.addItem('D')
self.cb.addItem('E')
self.show()
#pyqtSlot()
def cb_get(self):
global s
s = str(self.cb.currentText())
def p(self):
print(s)
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = App()
sys.exit(app.exec_())
Well, at least now it has ist own function and I can write code for it seperately.
def initUI(self):
#Buttons
btnposx = 30
btnposy = 50
self.btn4 = QPushButton('GetValue', self)
self.btn4.move(btnposx,btnposy+220)
self.btn4.clicked.connect(self.cb_get)
self.cb = QComboBox(self)
self.cb.move(btnposx+120,btnposy+150)
self.cb.resize(80,22)
self.cb.setMaximumSize(QSize(80,1000000))
self.cb.addItem('A')
self.cb.addItem('B')
self.cb.addItem('C')
self.cb.addItem('D')
self.cb.addItem('E')
self.s = None # initialize it here so you don't have to use global
self.show()
#pyqtSlot()
def cb_get(self):
cbtext = str(self.cb.currentText())
self.s = cbtext
def get_s(self):
return self.s
and
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = App()
# print(ex.get_s) # this won't work since you have to click on btn4 first
sys.exit(app.exec_())

Categories