I'm in big trouble, I can't figure it out how to open my window "PlotWindow" with my "OpendPlotWindow" function. I'm new in PyQt so it is a dumb question, but I really don't understand what's wrong in my code
PlotWindow:
class PlotWindoW(QDialog):
def __init__(self,x,y, parent=None):
super(Window, self).__init__(parent)
self.figure = plt.figure()
self.canvas = FigureCanvas(self.figure)
self.toolbar = NavigationToolbar(self.canvas, self)
self.plot(x,y)
layout = QVBoxLayout()
layout.addWidget(self.toolbar)
layout.addWidget(self.canvas)
self.setLayout(layout)
self.show()
def plot(self,x,y):
self.figure.clear()
ax = self.figure.add_subplot(111)
ax.plot(x,y)
self.canvas.draw()
PlotSetting:
class PlotSetting(QWidget):
def __init__(self,fileNameFm,fileNameMesh,fileNameSmry,fileNameXY, parent=None):
super(QWidget, self).__init__(parent)
print("setting start")
donnees.fileFm=fileNameFm
donnees.fileMesh=fileNameMesh
donnees.fileSmry=fileNameSmry
donnees.fileXY=fileNameXY
self.layout = QVBoxLayout(self)
self.tabs = QTabWidget()
self.tab1 = QWidget()
self.tabs.sizeHint()
self.tabs.addTab(self.tab1,"Setting Mesh")
LabelFm = QLabel(donnees.fileFm)
LabelMesh = QLabel(donnees.fileMesh)
btnNe=QPushButton("Choose Ne", self)
btnNe.clicked.connect(self.getInteger)
FmPlotBtn=QPushButton("Plot Mesh File", self)
FmPlotBtn.clicked.connect(self.GetDataFm)
self.tab1.layout = QVBoxLayout(self)
self.tab1.layout.addWidget(LabelFm)
self.tab1.layout.addWidget(LabelMesh)
self.tab1.layout.addWidget(btnNe)
self.tab1.layout.addWidget(FmPlotBtn)
self.tab1.setLayout(self.tab1.layout)
self.layout.addWidget(self.tabs)
self.setLayout(self.layout)
def getInteger(self):
donnees.Ne, okPressed = QInputDialog.getInt(self, "Get integer","Ne:", 66, 66, 98, 2)
if okPressed:
print(donnees.Ne)
def GetDataFm(self):
print('plot start')
data = {}
data = Fm( donnees.fileFm , donnees.fileMesh )
x,y=PloterFm(data,donnees.Ne)
print(x[0],y[0])
self.OpenPlotWindow(x,y)
def OpenPlotWindow(self, x, y):
print("OpenPlotWIndow is running")
print(x[0],y[0])
self.ThirdWindow = PlotWindoW(x,y)
self.ThirdWindow.show()
The problem: when I run my code, it comes to OpenPlotWindow which get all data needed, but it never enter into PlotWindow...
Please can you help me?
As per the docs for QPushButton's super class QAbstractButton, clicked takes one argument, bool checked = false. It's actually pretty useless on QPushButton as far as I've seen, but nevertheless, your function needs to account for this. Try this line instead
def GetDataFm(self, clicked=False):
....
Related
Im trying to get my windos better looking. To do this I wanted to use layout for the back button(B_btn). But I have no idea how to get it to apper in the bottom of the window. Hopefully this is not impossible but I am hard stuck..
class TestWindow(QWidget):
def __init__(self, parent=None):
super(TestWindow, self).__init__(parent)
self.B_btn = QPushButton('Back', self)
layout = QVBoxLayout()
layout.addWidget(self.B_btn)
self.setLayout(layout)
self.SJ_btn = QPushButton('Single jump', self)
self.SJ_btn.move(100, 100)
self.SJ_btn.resize(180,60)
self.SJI_btn = QPushButton('Info', self)
self.SJI_btn.move(100, 160)
self.SJI_btn.resize(180,20)
self.MJ_btn=QPushButton("Multiple jump", self)
self.MJ_btn.move(320,100)
self.MJ_btn.resize(180,60)
self.MJI_btn = QPushButton('Info', self)
self.MJI_btn.move(320, 160)
self.MJI_btn.resize(180,20)
self.DT_btn = QPushButton('Drift test', self)
self.DT_btn.move(100, 200)
self.DT_btn.resize(180,60)
self.DTI_btn = QPushButton('Info', self)
self.DTI_btn.move(100, 260)
self.DTI_btn.resize(180,20)
Okey now I did get it, its a stretcher i need. Thanks a lot!! If anyone know how to change the size of buttons in a layout I would be thankfull
When I decrease the window size all the widgets disappear.I want the widgets to move along when size is decreased.How do I solve this problem?
I have a drop-down menu from which a value is selected.When an "Add cmd" button is pressed the value is added to edit box.
Thanks in advance.
import sys
from PyQt4.QtCore import *
from PyQt4.QtGui import *
class tabdemo(QTabWidget):
def __init__(self, parent = None):
super(tabdemo, self).__init__(parent)
self.setGeometry(50, 50, 400,400)
QShortcut(QKeySequence("Esc"), self, self.close)
self.tab1 = QWidget()
self.tab2 = QWidget()
self.addTab(self.tab1,"Tab 1")
self.tab1UI()
self.setWindowTitle("Main Window")
def tab1UI(self):
self.comboBox = QComboBox(self.tab1)
self.comboBox.addItem('ABC')
self.comboBox.addItem('BCD')
self.comboBox.addItem('CDE')
self.comboBox.move(5,20)
self.comboBox.resize(180,30)
self.button = QPushButton('Add Cmd', self.tab1)
self.button.move(190,20)
self.button.resize(80,30)
self.button.clicked.connect(self.handleTest)
self.b = QTextEdit(self.tab1)
self.b.move(20,75)
self.b.resize(290,200)
self.button = QPushButton('Send Batch', self.tab1)
self.button.move(40,300)
self.button.resize(150,30)
self.button = QPushButton('Clear', self.tab1)
self.button.move(200,300)
self.button.resize(80,30)
self.button.clicked.connect(self.deletevalue)
layout = QFormLayout()
self.setTabText(4,"BatchCMDS")
self.tab1.setLayout(layout)
def handleTest(self):
self.b.append(str(self.comboBox.currentText()))
def deletevalue(self):
self.b.clear()
def main():
app = QApplication(sys.argv)
ex = tabdemo()
ex.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
If you want the widgets to adapt to the size of the window you should use layouts, For this, the application must be designed, for this an image is used of how you want your application to be:
As we see the widgets that are inside a tab are divided into 3 groups, the first is made up of the QComboBox with the QPushButton, the second the QTextEdit, and the third the 2 remaining buttons. Each group is horizontally distributed, so in that case we should use QHBoxLayout except the QTextEdit that is alone, and each group should be in QVBoxLayout. I do not understand why you use the QFormLayout, also if you use the layouts the positions are not necessary.
Another error that I see in your code is that several buttons have the same name, this causes errors like for example that the Add CMD button does not work, you must give a different name to each widget.
class tabdemo(QTabWidget):
def __init__(self, parent = None):
super(tabdemo, self).__init__(parent)
self.setGeometry(50, 50, 400,400)
QShortcut(QKeySequence("Esc"), self, self.close)
self.tab1 = QWidget()
self.tab2 = QWidget()
self.addTab(self.tab1,"Tab 1")
self.addTab(self.tab2,"Tab 2")
self.tab1UI()
def tab1UI(self):
vlayout = QVBoxLayout(self.tab1)
hlayout1 = QHBoxLayout()
self.comboBox = QComboBox(self.tab1)
self.comboBox.addItems(['ABC', 'BCD', 'CDE'])
self.button = QPushButton('Add Cmd', self.tab1)
self.button.clicked.connect(self.handleTest)
hlayout1.addWidget(self.comboBox)
hlayout1.addWidget(self.button)
hlayout1.addItem(QSpacerItem(100, 10, QSizePolicy.Expanding, QSizePolicy.Preferred))
vlayout.addLayout(hlayout1)
self.b = QTextEdit(self.tab1)
vlayout.addWidget(self.b)
hlayout2 = QHBoxLayout()
self.buttonSend = QPushButton('Send Batch', self.tab1)
self.buttonClear = QPushButton('Clear', self.tab1)
self.buttonClear.clicked.connect(self.deletevalue)
hlayout2.addItem(QSpacerItem(100, 10, QSizePolicy.Expanding, QSizePolicy.Preferred))
hlayout2.addWidget(self.buttonSend)
hlayout2.addWidget(self.buttonClear)
hlayout2.addItem(QSpacerItem(100, 10, QSizePolicy.Expanding, QSizePolicy.Preferred))
vlayout.addLayout(hlayout2)
self.setTabText(4,"BatchCMDS")
def handleTest(self):
self.b.append(self.comboBox.currentText())
def deletevalue(self):
self.b.clear()
I'm making a GUI which is to have a couple user input boxes and a plot which will use factors in the input boxes to scale data. The GUI will need an apply button and an export button. I am using PyQt5 for the GUI and Matplotlib for the plotting. My approach has been to create separate QWidgets for the plot and the input boxes and tie them together in a third QMainWindow.
I have the GUI appearing correctly
How can I get the apply button to send the 3 variables across to the main class and to the plotting class? Would it be possible to have all of this happen within one class to simplify how my variables will work?
import sys
import matplotlib
matplotlib.use("Qt5Agg")
from PyQt5 import QtCore
from PyQt5.QtCore import pyqtSlot, pyqtSignal, QObject
from PyQt5.QtWidgets import *
from numpy import arange, sin, pi
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.figure import Figure
class AppForm(QWidget):
def __init__(self):
# Initialize the object as a QWidget and
# set its title and minimum width
QWidget.__init__(self)
self.setWindowTitle('Input')
self.setMinimumWidth(400)
# Create the QVBoxLayout that lays out the whole form
self.layout = QVBoxLayout()
# Create the form layout that manages the labeled controls
self.form_layout = QFormLayout()
self.aFactor = QLineEdit(self)
self.mFactor = QLineEdit(self)
self.cZone = QLineEdit(self)
self.form_layout.addRow('AFactor', self.aFactor)
self.form_layout.addRow('MFactor', self.mFactor)
self.form_layout.addRow('CZone', self.cZone)
self.layout.addLayout(self.form_layout)
self.button_box = QHBoxLayout()
self.button_box.addStretch(1)
self.apply_button = QPushButton("Apply", self)
self.output_button = QPushButton("Output", self)
self.button_box.addWidget(self.apply_button)
self.button_box.addWidget(self.output_button)
self.layout.addLayout(self.button_box)
self.setLayout(self.layout)
self.apply_button.clicked.connect(self.applyButton)
def applyButton(self):
self.af = self.aFactor
self.mf = self.mFactor
self.cz = self.cZone
print self.af.text(), self.mf.text(), self.cz.text()
class MyMplCanvas(FigureCanvas):
"""Ultimately, this is a QWidget (as well as a FigureCanvasAgg, etc.)."""
def __init__(self, parent=None, width=5, height=4, dpi=100, title='title'):
self.title = title
fig = Figure(figsize=(width, height), dpi=dpi)
self.axes = fig.add_subplot(111)
fig.suptitle(title)
# We want the axes cleared every time plot() is called
self.axes.hold(False)
self.compute_initial_figure()
FigureCanvas.__init__(self, fig)
self.setParent(parent)
FigureCanvas.setSizePolicy(self,
QSizePolicy.Expanding,
QSizePolicy.Expanding)
FigureCanvas.updateGeometry(self)
def compute_initial_figure(self):
pass
class MyStaticMplCanvas(MyMplCanvas):
"""Simple canvas with a sine plot."""
def compute_initial_figure(self):
t = arange(0.0, 3.0, 0.01)
s = sin(2*pi*t)
self.axes.plot(t, s)
self.axes.set_ylabel('label1')
self.axes.set_xlabel('label')
self.axes.grid(True)
class ApplicationWindow(QMainWindow):
def __init__(self):
QMainWindow.__init__(self)
self.setAttribute(QtCore.Qt.WA_DeleteOnClose)
self.setWindowTitle("application main window")
self.setMinimumWidth(800)
self.setMinimumHeight(600)
self.file_menu = QMenu('&File', self)
self.file_menu.addAction('&Quit', self.fileQuit,
QtCore.Qt.CTRL + QtCore.Qt.Key_Q)
self.menuBar().addMenu(self.file_menu)
self.help_menu = QMenu('&Help', self)
self.menuBar().addSeparator()
self.menuBar().addMenu(self.help_menu)
self.help_menu.addAction('&About', self.about)
self.main_widget = QWidget(self)
l = QVBoxLayout(self.main_widget)
form = AppForm()
sc = MyStaticMplCanvas(self.main_widget, width=5, height=4, dpi=100, title='Title 1')
l.addWidget(form)
l.addWidget(sc)
self.main_widget.setFocus()
self.setCentralWidget(self.main_widget)
#self.statusBar().showMessage("Cool", 2000
def fileQuit(self):
self.close()
def closeEvent(self, ce):
self.fileQuit()
def about(self):
QMessageBox.about(self, "About",)
if __name__ == '__main__':
app = QApplication(sys.argv)
aw = ApplicationWindow()
aw.setWindowTitle("PyQt5 Matplot Example")
aw.show()
#sys.exit(qApp.exec_())
app.exec_()
There are several options here:
(a) Peform the work in the main class:
Instead of connecting the button in the AppForm to a method in AppForm, do the same in the ApplicationWindow.
self.form = AppForm()
self.sc = MyStaticMplCanvas(....)
self.form.apply_button.clicked.connect(self.applyButton)
def applyButton(self):
tx = self.form.aFactor.text()
# do something with tx
# e.g. call a method from MplCanvas
self.sc.someMethod(tx)
(b) Use signals and slots:
Create a signla in AppForm. Once the button is clicked, applyButton may emit this signal with the relevant content. In ApplicationWindow connect that signal to a method which can use the supplied data in some way. You can also connect it directly to a method of MplCanvas.
class AppForm(QWidget):
mysignal = pyqtSignal(object)
def __init__(self):
....
self.apply_button.clicked.connect(self.applyButton)
def applyButton(self):
self.mysignalemit((self.aFactor.text(),self.mFactor.text(), self.cZone()) )
class ApplicationWindow(QMainWindow):
def __init__(self):
....
self.form = AppForm()
self.sc = MyStaticMplCanvas(....)
self.form.mysignal.connect(self.useButtonResults)
self.form.mysignal.connect(self.sc.someMethod)
def useButtonResults(self, obj):
a,b,c = obj
# do something with a, b, c
(c) Use a single class to do everything:
Just put everything in a single class and do whatever you like.
I am writing a program which is supposed to give me data of a chart when I click certain buttons. I have given the program as far as I am right now. (I still have to connect the last 4 buttons but the first one works.) Now there is another problem: I used to have a chart displayed as I clicked on "One Plot" but since I activated "First Button", the chart does not appear anymore due to the problem mentioned problem. This is the script:
class Main(QMainWindow, Ui_MainWindow):
def __init__(self, parent=None):
super(Main, self).__init__(parent)
self.setupUi(self)
self.fig_dict = {}
self.mplfigs.itemClicked.connect(self.changefig)
self.button1.setText("First Point")
self.button1.clicked.connect(self.onClickButton1)
self.dialogbutton1 = PopUp(self)
fig = Figure()
self.addmpl(fig)
#QtCore.pyqtSlot()
def changefig(self, item):
text = item.text()
self.rmmpl()
self.addmpl(self.fig_dict[str(text)])
def addfig(self, name, fig):
self.fig_dict[name] = fig
self.mplfigs.addItem(name)
def addmpl(self, fig):
self.canvas = FigureCanvas(fig)
self.mplvl.addWidget(self.canvas)
self.canvas.draw()
self.toolbar = NavigationToolbar(self.canvas, self.mplwindow, coordinates=True)
self.mplvl.addWidget(self.toolbar)
def onClickButton1(self):
# When button 1 is clicked, I do the following
print "does nothing now."
self.dialogbutton1.exec_()
def rmmpl(self,):
self.mplvl.removeWidget(self.canvas)
self.canvas.close()
self.mplvl.removeWidget(self.toolbar)
self.toolbar.close()
class PopUp(QtGui.QDialog):
def __init__(self, parent=None):
super(PopUp, self).__init__(parent)
self.buttonBox = QtGui.QDialogButtonBox(self)
self.buttonBox.setOrientation(QtCore.Qt.Horizontal)
self.buttonBox.setStandardButtons(QtGui.QDialogButtonBox.Cancel|QtGui.QDialogButtonBox.Ok)
self.textBrowser = QtGui.QTextBrowser(self)
self.textBrowser.append("x - Coordinate = 0 y - Coordinate = 0.031451")
self.verticalLayout = QtGui.QVBoxLayout(self)
self.verticalLayout.addWidget(self.textBrowser)
self.verticalLayout.addWidget(self.buttonBox)
if __name__ == '__main__':
import sys
from PyQt4 import QtGui
import numpy as np
fig1 = Figure()
ax1f1 = fig1.add_subplot(111)
ax1f1.plot(np.random.rand(5))
app = QtGui.QApplication(sys.argv)
main = Main()
main.addfig('One plot', fig1)
print main.fig_dict
main.show()
sys.exit(app.exec_())
In class Main, you are calling changefig function as self.mplfigs.itemClicked.connect(self.changefig).
But function definition of changefig is def changefig(self, item): which expects two arguments - self and item.
When you called changefig - self.mplfigs.itemClicked.connect(self.changefig), only self is passed. But item is not passed.
That's why you are getting that error.
It should be self.mplfigs.itemClicked.connect(self.changefig(item))
First, I started using PyQt few hours ago.
So far so good - im writing rss client to familiarize myself with PyQt
I got QApplication, QMainWindow and two custom widgets.
First custom widget is:
class RssItem(QWidget):
__pyqtSignals__ = ("articleViewed(bool)",
"articleOpened(bool)",
"articleMarkedGood(bool)")
def __init__(self, title, date, parent = None):
super(RssItem, self).__init__(parent)
self.initWidget(title, date)
def initWidget(self, title, date):
title = QLabel(title)
date = QLabel(date)
titleBox = QHBoxLayout()
titleBox.addWidget(title)
titleBox.addWidget(date)
self.setLayout(titleBox)
That displays (for now) title and date in single row
Second one accepts array of RssItem widgets and display them in vertical list:
class ItemsList(QWidget):
def __init__(self, items, parent=None):
super(ItemsList, self).__init__(parent)
self.initWidget(items)
def initWidget(self, items):
listBox = QVBoxLayout(self)
for item in items:
listBox.addWidget(item)
listBox.addStretch(1)
self.setLayout(listBox)
How do I make this list scrollable?
Keep in mid I'm planing to have multiple ItemList's in one window each should have it's own scrollbar.
Main app function as for now is only for testing these 2 widgets:
class MainApp(Qt.QApplication):
def __init__(self, args):
super(MainApp, self).__init__(args)
self.addWidgets()
self.exec_()
def addWidgets(self):
self.window = MainWindow()
class MainWindow(QtGui.QMainWindow):
def __init__(self):
super(MainWindow, self).__init__()
self.initUI()
def initUI(self):
self.statusBar().showMessage("ok")
self.resize(640, 480)
self.setWindowTitle("Smart Rss")
items=[]
for x in range(0, 200):
items.append(RssItem("Title no %s" % x, "2000-1-%s" %x))
self.setCentralWidget(ItemsList(items))
self.show()
EDIT:Getting closer, changed ItemList.initWidget to
def initWidget(self, items):
scroll= QScrollArea(self)
wrap = QWidget(self)
listBox = QVBoxLayout(self)
for item in items:
listBox.addWidget(item)
listBox.addStretch(1)
wrap.setLayout(listBox)
scroll.setWidget(wrap)
But now I cant figure out how to make QScrollArea fill all available space and auto resize when it's changed.
Try scroll.setWidgetResizable(True) like in here:
def initWidget(self, items):
listBox = QVBoxLayout(self)
self.setLayout(listBox)
scroll = QScrollArea(self)
listBox.addWidget(scroll)
scroll.setWidgetResizable(True)
scrollContent = QWidget(scroll)
scrollLayout = QVBoxLayout(scrollContent)
scrollContent.setLayout(scrollLayout)
for item in items:
scrollLayout.addWidget(item)
scroll.setWidget(scrollContent)