I am trying to create plots with a Python GUI and gnuplot.
I am generating the code in Python and send it to gnuplot.
This basically works with piping data to gnuplot, but:
Disadvantages:
the Python program is blocked until you close gnuplot
you have to load/start gnuplot again and again everytime you're making a plot which seems to take annoying extra time (on slow computers)
My questions:
how to keep the Python program responsive?
is there a way to start gnuplot once and keep it running?
how to just update the gnuplot terminal if there is a new plot?
Thank you for hints and links.
Here is my code:
import sys
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout, QPlainTextEdit, QPushButton
import subprocess
class MyWindow(QWidget):
def __init__(self):
super(MyWindow,self).__init__()
self.setGeometry(100,100,400,200)
self.myTextEdit = QPlainTextEdit()
self.myTextEdit.setPlainText("plot sin(x)")
self.button = QPushButton('Plot code',self)
self.button.clicked.connect(self.on_button_click)
vbox = QVBoxLayout(self)
vbox.addWidget(self.myTextEdit)
vbox.addWidget(self.button)
self.setLayout(vbox)
#pyqtSlot()
def on_button_click(self):
gnuplot_str = self.myTextEdit.document().toPlainText() + "\n"
gnuplot_path = r'C:\Programs\gnuplot\bin\gnuplot.exe'
plot = subprocess.Popen([gnuplot_path,'-p'],stdin=subprocess.PIPE)
plot.communicate(gnuplot_str.encode())
if __name__ == '__main__':
app = QApplication(sys.argv)
window = MyWindow()
window.show()
sys.exit(app.exec_())
Instead of using subprocess you must use QProcess which is friendly to the Qt event loop as I show below:
import sys
from PyQt5.QtCore import QProcess, pyqtSlot
from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout, QPlainTextEdit, QPushButton
class MyWindow(QWidget):
def __init__(self):
super(MyWindow,self).__init__()
self.setGeometry(100,100,400,200)
self.myTextEdit = QPlainTextEdit()
self.myTextEdit.setPlainText("plot sin(x)")
self.button = QPushButton('Plot code',self)
self.button.clicked.connect(self.on_button_click)
vbox = QVBoxLayout(self)
vbox.addWidget(self.myTextEdit)
vbox.addWidget(self.button)
gnuplot_path = r'C:\Programs\gnuplot\bin\gnuplot.exe'
self.process = QProcess(self)
self.process.start(gnuplot_path, ["-p"])
#pyqtSlot()
def on_button_click(self):
gnuplot_str = self.myTextEdit.document().toPlainText() + "\n"
self.process.write(gnuplot_str.encode())
if __name__ == '__main__':
app = QApplication(sys.argv)
window = MyWindow()
window.show()
sys.exit(app.exec_())
Related
Both of the following codes are codes that show empty gui. But the code above is QMainWindow
From PyQt5.QtWidgets import QApplication, QMainWindow Use this and the code below is uic.loadUiType. If you look on the Internet, you can't see the difference between the two codes, some using the above and some using the below code. I ask you to explain about this.
#---------------------------upside code------------------------#
import sys
from PyQt5.QtWidgets import QApplication
from PyQt5 import uic
[form_class,QMainWindow]=uic.loadUiType('uifile.ui')
class Main(form_class,QMainWindow):
def __init__(self):
super().__init__()
self.setupUi(self)
if __name__ == '__main__':
app = QApplication(sys.argv)
main = Main()
main.show()
app.exec()
#---------------------------downside code------------------------#
import sys
from PyQt5.QtWidgets import QApplication, QMainWindow
from PyQt5 import uic
form_class=uic.loadUiType('uifile.ui')[0]
class Main(form_class,QMainWindow):
def __init__(self):
super().__init__()
self.setupUi(self)
if __name__ == '__main__':
app = QApplication(sys.argv)
main = Main()
main.show()
app.exec()
I am developing a PyQt5 application however I am having issues with the heights of the widgets. Below is a simplified version of my issue:
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtWebEngineWidgets import QWebEngineView
from PyQt5.QtCore import *
from PyQt5.QtGui import *
class App(QWidget):
def __init__(self):
super().__init__()
self.showMaximized()
self.setStyleSheet("QWidget {background: blue;}")
print(self.frameGeometry().height())
self.show()
if __name__ == "__main__":
window = QApplication(sys.argv)
app = App()
window.setStyle(QStyleFactory.create("Fusion"))
window.exec_()
Here I create a window and maximise it. Using a tkinter window, it tells me the height maximised is 841, which is the size of my screen, however the PyQt5 application prints the height to be 519. Is this an issue with the self.showMaximized() method, or some other issue.
Resizing is not instantaneous in Qt. What Qt does is take the information from showMaximized to activate the flag of the native window (library that depends on each OS) then after a time T the OS applies that flag and sends it the new geometry. So in your case you have to give it a delay to get the correct information.
import sys
from PyQt5.QtWidgets import QApplication, QStyleFactory, QWidget
from PyQt5.QtCore import QTimer
class App(QWidget):
def __init__(self):
super().__init__()
self.setStyleSheet("QWidget {background: blue;}")
self.showMaximized()
QTimer.singleShot(100, self.calculate)
def calculate(self):
print(self.frameGeometry().height())
if __name__ == "__main__":
window = QApplication(sys.argv)
app = App()
window.setStyle(QStyleFactory.create("Fusion"))
window.exec_()
On the other hand, if your objective is to know the size of the initial screen then you should not use a QWidget for that since it will depend on the time it takes for Qt and the native library to create the native window, instead use the Screen class :
import sys
from PyQt5.QtWidgets import QApplication
from PyQt5.QtGui import QGuiApplication
if __name__ == "__main__":
window = QApplication(sys.argv)
print(QGuiApplication.primaryScreen().availableGeometry().height())
I want to create a splash screen in PyQt5 using Python. I searched but I found in Pyqt4 and I have no understanding of PyQt4 so help me in this case I would be gratful
Splash screen in pyqt
I like to add it in just before i load my main widget with a slight fade - note this is only useful to show a logo, if your application has a long load time you can utilise the splash screen like #S. Nick has shown to allow load time whilst you show the splashscreen:
from PyQt5 import QtGui, QtCore, QtWidgets
import time
if __name__ == '__main__':
app = QtWidgets.QApplication([])
# Create splashscreen
splash_pix = QtGui.QPixmap('picture.png')
splash = QtWidgets.QSplashScreen(splash_pix, QtCore.Qt.WindowStaysOnTopHint)
# add fade to splashscreen
opaqueness = 0.0
step = 0.1
splash.setWindowOpacity(opaqueness)
splash.show()
while opaqueness < 1:
splash.setWindowOpacity(opaqueness)
time.sleep(step) # Gradually appears
opaqueness+=step
time.sleep(1) # hold image on screen for a while
splash.close() # close the splash screen
#widget = YourWidget()
#widget.show() # This is where you'd run the normal application
app.exec_()
Try it:
import sys
from PyQt5.QtGui import QPixmap
from PyQt5.QtWidgets import QDialog, QPushButton, QVBoxLayout, QApplication, QSplashScreen
from PyQt5.QtCore import QTimer
class Dialog(QDialog):
def __init__(self, parent=None):
super(Dialog, self).__init__(parent)
self.b1 = QPushButton('Display screensaver')
self.b1.clicked.connect(self.flashSplash)
layout = QVBoxLayout()
self.setLayout(layout)
layout.addWidget(self.b1)
def flashSplash(self):
self.splash = QSplashScreen(QPixmap('D:/_Qt/img/pyqt.jpg'))
# By default, SplashScreen will be in the center of the screen.
# You can move it to a specific location if you want:
# self.splash.move(10,10)
self.splash.show()
# Close SplashScreen after 2 seconds (2000 ms)
QTimer.singleShot(2000, self.splash.close)
if __name__ == '__main__':
app = QApplication(sys.argv)
main = Dialog()
main.show()
sys.exit(app.exec_())
Example 2
import sys
from PyQt5 import QtCore, QtGui, QtWidgets # + QtWidgets
import sys
from PyQt5.QtWidgets import QApplication, QLabel
from PyQt5.QtCore import QTimer, Qt
if __name__ == '__main__':
app = QApplication(sys.argv)
label = QLabel("""
<font color=red size=128>
<b>Hello PyQt, The window will disappear after 5 seconds!</b>
</font>""")
# SplashScreen - Indicates that the window is a splash screen. This is the default type for .QSplashScreen
# FramelessWindowHint - Creates a borderless window. The user cannot move or resize the borderless window through the window system.
label.setWindowFlags(Qt.SplashScreen | Qt.FramelessWindowHint)
label.show()
# Automatically exit after 5 seconds
QTimer.singleShot(5000, app.quit)
sys.exit(app.exec_())
The simple and best example that I found.
https://www.youtube.com/watch?v=TsatZJfzb_Q&t=162s
from PyQt5.QtWidgets import QMainWindow, QApplication, QDialog
from PyQt5.QtWidgets import QGraphicsScene,QSplashScreen
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QPixmap
class SplashScreen(QSplashScreen):
def __init__(self):
super(QSplashScreen, self).__init__()
loadUi("splash.ui", self)
self.setWindowFlag(Qt.FramelessWindowHint)
pixmap = QPixmap("any_image.jpg")
self.setPixmap(pixmap)
def progress(self):
for i in range(40):
time.sleep(0.1)
self.progressBar.setValue(i)
class MainScreen(QMainWindow):
def function1():
.......
def function2():
......
if __name__ == "__main__":
app = QApplication(sys.argv)
splash = SplashScreen()
splash.show()
splash.progress()
mainscreen = MainScreen()
mainscreen.show()
splash.finish(widget)
sys.exit(app.exec_())
So I've been trying to create my own terminal but that has been proven very glitchy and not professional looking.
Then I stumbled across this code which is for PyQt4:
#!/usr/bin/env python
#-*- coding:utf-8 -*-
import sys
from PyQt4.QtCore import *
from PyQt4.QtGui import *
class embterminal(QWidget):
def __init__(self):
QWidget.__init__(self)
self.process = QProcess(self)
self.terminal = QWidget(self)
layout = QVBoxLayout(self)
layout.addWidget(self.terminal)
#self.process.start(
#'xterm',['-into', str(self.terminal.winId())])
# Works also with urxvt:
self.process.start(
'urxvt',['-embed', str(self.terminal.winId())])
if __name__ == "__main__":
app = QApplication(sys.argv)
main = embterminal()
main.show()
sys.exit(app.exec_())
Since my application is written in PyQt5, I naturally tried porting that code to PyQt5.
I changed from PyQt4.QtCore import *
from PyQt4.QtGui import * to from PyQt5.QtCore import *
from PyQt5.QtGui import * and added from PyQt5.QtWidgets import *
Then when I ran my code I realized the terminal didn't pop up.
I wonder why does this happen and is there a workaround ?
I also wonder if I can use both PyQt5 and PyQt4 in the same project/file, even.
In PyQt. QWidget.winId() returns a sip.voidptr object, but if you convert it to an integer, it should work. Here's a working example:
import sys
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
class Window(QWidget):
def __init__(self):
super().__init__()
self.process = QProcess(self)
self.terminal = QWidget(self)
layout = QVBoxLayout(self)
layout.addWidget(self.terminal)
wid = str(int(self.terminal.winId()))
self.process.start('urxvt', ['-embed', wid])
def closeEvent(self, event):
self.process.terminate()
self.process.waitForFinished(1000)
if __name__ == "__main__":
app = QApplication(sys.argv)
window = Window()
window.setGeometry(100, 100, 800, 600)
window.show()
sys.exit(app.exec_())
I am making a gui using pyqt4. When I insert data from sqlite into my qtablewidget table, it will only update itself once I have closed the program and reopened it. How can I have the program update itself automatically (refresh the class) after inserting/deleting or changing the data in anyway?
Since I am not sure how you are implementing your code, maybe the following code helps you.
#!/usr/bin/python
import sys
from PyQt4.QtGui import QWidget, QPushButton, QMainWindow, QTableWidget,QTableWidgetItem, QVBoxLayout, QApplication
from PyQt4.QtCore import Qt
class MyMainWindow(QMainWindow):
def __init__(self, parent=None):
"""
"""
super(MyMainWindow,self).__init__(parent)
self.setWidgets()
def setWidgets(self, ):
vBox = QVBoxLayout()
mainFrame = QWidget()
self._pressButton = QPushButton("Update Table",self)
self._pressButton.clicked.connect(self.updateTable)
self._table = QTableWidget(self)
self._table.setRowCount(3)
self._table.setColumnCount(3)
vBox.addWidget(self._pressButton)
vBox.addWidget(self._table)
mainFrame.setLayout(vBox)
self.setCentralWidget(mainFrame)
def updateTable(self, ):
i = self._table.currentRow()
if i == -1:
i=0
self._table.insertRow(i)
self._table.setItem(i,0,QTableWidgetItem("Test"))
if __name__ == '__main__':
qApp = QApplication(sys.argv)
MainWindow = MyMainWindow()
MainWindow.show()
sys.exit(qApp.exec_())
Cheers