mpylayer, PyQt4 and lineEdit - python

Consider the minimal example below. It works perfectly until I uncomment the following lines:
# self.mainwi = QtGui.QWidget(self)
# self.lineEdit1 = QtGui.QLineEdit(self.mainwi)
# self.setCentralWidget(self.lineEdit1)
If those lines are uncommented, I can write text in the LineEdit-field, but the buttons don't react. Any idea what's wrong with it, how to fix this?
I should add that I am an absolute beginner in programming python.
#!/usr/bin/python
import mpylayer
import sys
from PyQt4 import QtCore
from PyQt4 import QtGui
class DmplayerGUI(QtGui.QMainWindow):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)
self.dirty = False
self.mp = mpylayer.MPlayerControl()
#Toolbar
## items
### Play
self.play = QtGui.QAction(QtGui.QIcon('icons/play_32.png'), 'Play', self)
self.play.setShortcut('Ctrl+A')
self.connect(self.play, QtCore.SIGNAL('triggered()'), self.DPlay)
### Pause
self.pause = QtGui.QAction(QtGui.QIcon('icons/pause_32.png'), 'Pause', self)
self.pause.setShortcut('Ctrl+P')
self.connect(self.pause, QtCore.SIGNAL('triggered()'), self.DPause)
## toolbar
self.toolbar = self.addToolBar('Toolbar')
self.toolbar.addAction(self.play)
self.toolbar.addAction(self.pause)
# self.mainwi = QtGui.QWidget(self)
# self.lineEdit1 = QtGui.QLineEdit(self.mainwi)
# self.setCentralWidget(self.lineEdit1)
# play
def DPlay(self):
self.mp.loadfile('video.mp4')
# pause
def DPause(self):
self.mp.pause(self)
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
dp = DmplayerGUI()
dp.show()
sys.exit(app.exec_())

You do not need the mainwi at all in this simple example. Just do
self.lineEdit1 = QtGui.QLineEdit(self)
self.setCentralWidget(self.lineEdit1)
In case you really wanted it, then you need to set the mainwi as the centralwidget
self.mainwi = QtGui.QWidget(self)
self.lineEdit1 = QtGui.QLineEdit(self.mainwi)
self.setCentralWidget(self.mainwi)
do not forget to add some layout for mainwi, since this looks ugly :-)
Anyway, I have to admit, that I do not know why exactly does it "disable" the buttons. But the central widget has to be a child of the window as far as I know.

Related

PyQt5 removing button

In the list_widget I have added a add button I also want to add a remove button which asks which item you wants to remove and remove the chosen item. I was trying it to do but I didn't had any idea to do so .Also, please explain the solution I am a beginner with pyqt5 or I'd like to say absolute beginner.
from PyQt5 import QtWidgets
from PyQt5.QtWidgets import QApplication,QMainWindow,
QListWidget, QListWidgetItem
import sys
class MyWindow(QMainWindow):
def __init__(self):
super(MyWindow, self).__init__()
self.x = 200
self.y = 200
self.width = 500
self.length = 500
self.setGeometry(self.x, self.y, self.width,
self.length)
self.setWindowTitle("Stock managment")
self.iniTUI()
def iniTUI(self):
# buttons
self.b1 = QtWidgets.QPushButton(self)
self.b1.setText("+")
self.b1.move(450, 100)
self.b1.resize(50, 25)
self.b1.clicked.connect(self.take_inputs)
# This is the button I want to define.
self.btn_minus = QtWidgets.QPushButton(self)
self.btn_minus.setText("-")
self.btn_minus.move(0, 100)
self.btn_minus.resize(50, 25)
# list
self.list_widget = QListWidget(self)
self.list_widget.setGeometry(120, 100, 250, 300)
self.item1 = QListWidgetItem("A")
self.item2 = QListWidgetItem("B")
self.item3 = QListWidgetItem("C")
self.list_widget.addItem(self.item1)
self.list_widget.addItem(self.item2)
self.list_widget.addItem(self.item3)
self.list_widget.setCurrentItem(self.item2)
def take_inputs(self):
self.name, self.done1 =
QtWidgets.QInputDialog.getText(
self, 'Add Item to List', 'Enter The Item you want
in
the list:')
self.roll, self.done2 = QtWidgets.QInputDialog.getInt(
self, f'Quantity of {str(self.name)}', f'Enter
Quantity of {str(self.name)}:')
if self.done1 and self.done2:
self.item4 = QListWidgetItem(f"{str(self.name)}
Quantity{self.roll}")
self.list_widget.addItem(self.item4)
self.list_widget.setCurrentItem(self.item4)
def clicked(self):
self.label.setText("You clicked the button")
self.update()
def update(self):
self.label.adjustSize()
def clicked():
print("meow")
def window():
apk = QApplication(sys.argv)
win = MyWindow()
win.show()
sys.exit(apk.exec_())
window()
The core issue here is the lack of separation of the view and the data. This makes it very hard to reason about how to work with graphical elements. You will almost certainly want to follow the Model View Controller design paradigm https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller
which offers a systematic way to handle this separation.
Once you do so, it immediately becomes very straight forward how to proceed with the question: You essentially just have a list, and you either want to add a thing to this list, or remove one based on a selection.
I include an example here which happens to use the built-in classes QStringListModel and QListView in Qt5, but it is simple to write your own more specialized widgets and models. They all just use a simple signal to emit to the view that it needs to refresh the active information.
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
import sys
class StuffViewer(QMainWindow):
def __init__(self, model):
super().__init__()
self.setWindowTitle("Stock managment")
# 1: Use layouts.
hbox = QHBoxLayout()
widget = QWidget()
widget.setLayout(hbox)
self.setCentralWidget(widget)
# 2: Don't needlessly store things in "self"
vbox = QVBoxLayout()
add = QPushButton("+")
add.clicked.connect(self.add_new_stuff)
vbox.addWidget(add)
sub = QPushButton("-")
sub.clicked.connect(self.remove_selected_stuff)
vbox.addWidget(sub)
vbox.addStretch(1)
hbox.addLayout(vbox)
# 3: Separate the view of the data from the data itself. Use Model-View-Controller design to achieve this.
self.model = model
self.stuffview = QListView()
self.stuffview.setModel(self.model)
hbox.addWidget(self.stuffview)
def add_new_stuff(self):
new_stuff, success = QInputDialog.getText(self, 'Add stuff', 'Enter new stuff you want')
if success:
self.stuff.setStringList(self.stuff.stringList() + [new_stuff])
def remove_selected_stuff(self):
index = self.stuffview.currentIndex()
all_stuff = self.stuff.stringList()
del all_stuff[index.column()]
self.stuff.setStringList(all_stuff)
def window():
apk = QApplication(sys.argv)
# Data is clearly separated:
# 4: Never enumerate variables! Use lists!
stuff = QStringListModel(["Foo", "Bar", "Baz"])
# The graphical components is just how you interface with the data with the user!
win = StuffViewer(stuff)
win.show()
sys.exit(apk.exec_())
window()

How to have two widgets in one Main window

I am trying the whole morning already to fix that.
So I have a PyQt Main Window where I want to display two widgets.
In the first widget there are articles listed (which works so far).
When I click on them until now a QMessageBox is opening, but I want that
a second widget is opening where I can read the RSS Feed.
But this is not working. See Code below:
class ArticleWidgets(QWidget):
def __init__(self, *args):
super().__init__(*args)
self.setGeometry(610, 610, 600, 600)
self.initUi()
def initUi(self):
self.box = QHBoxLayout(self)
def show(self, feed=None):
self.title = QLabel()
self.summary = QLabel()
self.link = QLabel()
if feed:
self.title.setText(feed[0])
self.summary.setText(feed[1])
self.link.setText(feed[2])
self.box.addWidget(self.title)
self.box.addWidget(self.summary)
self.box.addWidget(self.link)
self.setLayout(self.box)
class TitleWidgets(QWidget):
def __init__(self, *args):
super().__init__(*args)
self.setGeometry(10, 10, 600, 600)
self.initUi()
def initUi(self):
vbox = QHBoxLayout(self)
self.titleList = QListWidget()
self.titleList.itemDoubleClicked.connect(self.onClicked)
self.titleList.setGeometry(0, 0, 400, 400)
self.news = ANFFeed()
for item in self.news.all_feeds:
self.titleList.addItem(item[0])
vbox.addWidget(self.titleList)
def onClicked(self, item):
feeds = self.news.all_feeds
id = 0
for elem in range(len(feeds)):
if feeds[elem][0] == item.text():
id = elem
summary = feeds[id][1] + '\n\n'
link = feeds[id][2]
if feeds and id:
#ANFApp(self).show_articles(feeds[id])
show = ANFApp()
show.show_articles(feed=feeds[id])
QMessageBox.information(self, 'Details', summary + link)
class ANFApp(QMainWindow):
def __init__(self, *args):
super().__init__(*args)
self.setWindowState(Qt.WindowMaximized)
self.setWindowIcon(QIcon('anf.png'))
self.setAutoFillBackground(True)
self.anfInit()
self.show()
def anfInit(self):
self.setWindowTitle('ANF RSS Reader')
TitleWidgets(self)
#article_box = ArticleWidgets(self)
exitBtn = QPushButton(self)
exitBtn.setGeometry(600, 600, 100, 50)
exitBtn.setText('Exit')
exitBtn.setStyleSheet("background-color: red")
exitBtn.clicked.connect(self.exit)
def show_articles(self, feed=None):
present = ArticleWidgets()
present.show(feed)
def exit(self):
QCoreApplication.instance().quit()
Solution using Pyqtgraph's Docks and QTextBrowser
Here is a code trying to reproduce your sketch. I used the Pyqtgraph module (Documentation here: Pyqtgraph's Documentation and Pyqtgraph's Web Page) because its Dock widget is easier to use and implement from my perspective.
You must install the pyqtgraph module before trying this code:
import sys
from PyQt5 import QtGui, QtCore
from pyqtgraph.dockarea import *
class DockArea(DockArea):
## This is to prevent the Dock from being resized to te point of disappear
def makeContainer(self, typ):
new = super(DockArea, self).makeContainer(typ)
new.setChildrenCollapsible(False)
return new
class MyApp(QtGui.QMainWindow):
def __init__(self):
QtGui.QMainWindow.__init__(self)
central_widget = QtGui.QWidget()
layout = QtGui.QVBoxLayout()
central_widget.setLayout(layout)
self.setCentralWidget(central_widget)
label = QtGui.QLabel('This is a label, The widgets will be below')
label.setMaximumHeight(15)
## The DockArea as its name says, is the are where we place the Docks
dock_area = DockArea(self)
## Create the Docks and change some esthetic of them
self.dock1 = Dock('Widget 1', size=(300, 500))
self.dock2 = Dock('Widget 2', size=(400, 500))
self.dock1.hideTitleBar()
self.dock2.hideTitleBar()
self.dock1.nStyle = """
Dock > QWidget {
border: 0px solid #000;
border-radius: 0px;
}"""
self.dock2.nStyle = """
Dock > QWidget {
border: 0px solid #000;
border-radius: 0px;
}"""
self.button = QtGui.QPushButton('Exit')
self.widget_one = WidgetOne()
self.widget_two = WidgetTwo()
## Place the Docks inside the DockArea
dock_area.addDock(self.dock1)
dock_area.addDock(self.dock2, 'right', self.dock1)
## The statment above means that dock2 will be placed at the right of dock 1
layout.addWidget(label)
layout.addWidget(dock_area)
layout.addWidget(self.button)
## Add the Widgets inside each dock
self.dock1.addWidget(self.widget_one)
self.dock2.addWidget(self.widget_two)
## This is for set the initial size and posotion of the main window
self.setGeometry(100, 100, 600, 400)
## Connect the actions to functions, there is a default function called close()
self.widget_one.TitleClicked.connect(self.dob_click)
self.button.clicked.connect(self.close)
def dob_click(self, feed):
self.widget_two.text_box.clear()
## May look messy but wat i am doing is somethin like this:
## 'Title : ' + feed[0] + '\n\n' + 'Summary : ' + feed[1]
self.widget_two.text_box.setText(
'Title : ' + feed[0]\
+ '\n\n' +\
'Summary : ' + feed[1]
)
class WidgetOne(QtGui.QWidget):
## This signal is created to pass a "list" when it (the signal) is emited
TitleClicked = QtCore.pyqtSignal([list])
def __init__(self):
QtGui.QWidget.__init__(self)
self.layout = QtGui.QVBoxLayout()
self.setLayout(self.layout)
self.titleList = QtGui.QListWidget()
self.label = QtGui.QLabel('Here is my list:')
self.layout.addWidget(self.label)
self.layout.addWidget(self.titleList)
self.titleList.addItem(QtGui.QListWidgetItem('Title 1'))
self.titleList.addItem(QtGui.QListWidgetItem('Title 2'))
self.titleList.itemDoubleClicked.connect(self.onClicked)
def onClicked(self, item):
## Just test values
title = item.text()
summary = "Here you will put the summary of {}. ".format(title)*50
## Pass the values as a list in the signal. You can pass as much values
## as you want, remember that all of them have to be inside one list
self.TitleClicked.emit([title, summary])
class WidgetTwo(QtGui.QWidget):
def __init__(self):
QtGui.QWidget.__init__(self)
self.layout = QtGui.QVBoxLayout()
self.setLayout(self.layout)
self.label2 = QtGui.QLabel('Here we show results?:')
self.text_box = QtGui.QTextBrowser()
self.layout.addWidget(self.label2)
self.layout.addWidget(self.text_box)
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
window = MyApp()
window.show()
sys.exit(app.exec_())
Again, there are comments inside the code to help you understand what I did.
Here is how it looks:
If you pass the mouse between the two widgets you will see the mouse icon will change, with that you can readjust on the run the size of both widgets.
Final Words
This is another approach, more "interactive" and more esthetic than my previous answer. As you said, using a QSplitter works too.
Problems
The way you are building your GUI is, in my opinion, messy and it may lead to errors. I suggest the use of Layouts for a more organized GUI.
The other problem is that each widget is an independent class so if you want to connect an action in one widget to do something in the other widget through the Main Window, you must use Signals.
Edit : Another suggestion, use other name for the close function instead of exit and try using self.close() instead of QCoreApplication.instance().quit()
Solution
Trying to emulate what you want to do I made this GUI:
import sys
from PyQt5 import QtGui, QtCore
class MyWindow(QtGui.QMainWindow):
def __init__(self):
QtGui.QMainWindow.__init__(self)
## Generate the structure parts of the MainWindow
self.central_widget = QtGui.QWidget() # A QWidget to work as Central Widget
self.layout1 = QtGui.QVBoxLayout() # Vertical Layout
self.layout2 = QtGui.QHBoxLayout() # Horizontal Layout
self.widget_one = WidgetOne()
self.widget_two = WidgetTwo()
self.exitBtn = QtGui.QPushButton('Exit')
## Build the structure
# Insert a QWidget as a central widget for the MainWindow
self.setCentralWidget(self.central_widget)
# Add a principal layout for the widgets/layouts you want to add
self.central_widget.setLayout(self.layout1)
# Add widgets/layuts, as many as you want, remember they are in a Vertical
# layout: they will be added one below of the other
self.layout1.addLayout(self.layout2)
self.layout1.addWidget(self.exitBtn)
# Here we add the widgets to the horizontal layout: one next to the other
self.layout2.addWidget(self.widget_one)
self.layout2.addWidget(self.widget_two)
## Connect the signal
self.widget_one.TitleClicked.connect(self.dob_click)
def dob_click(self, feed):
## Change the properties of the elements in the second widget
self.widget_two.title.setText('Title : '+feed[0])
self.widget_two.summary.setText('Summary : '+feed[1])
## Build your widgets same as the Main Window, with the excepton that here you don't
## need a central widget, because it is already a widget.
class WidgetOne(QtGui.QWidget):
TitleClicked = QtCore.pyqtSignal([list]) # Signal Created
def __init__(self):
QtGui.QWidget.__init__(self)
##
self.layout = QtGui.QVBoxLayout() # Vertical Layout
self.setLayout(self.layout)
self.titleList = QtGui.QListWidget()
self.label = QtGui.QLabel('Here is my list:')
self.layout.addWidget(self.label)
self.layout.addWidget(self.titleList)
self.titleList.addItem(QtGui.QListWidgetItem('Title 1'))
self.titleList.addItem(QtGui.QListWidgetItem('Title 2'))
self.titleList.itemDoubleClicked.connect(self.onClicked)
def onClicked(self, item):
## Just test parameters and signal emited
self.TitleClicked.emit([item.text(), item.text()+item.text()])
class WidgetTwo(QtGui.QWidget):
def __init__(self):
QtGui.QWidget.__init__(self)
self.layout = QtGui.QVBoxLayout()
self.setLayout(self.layout)
self.title = QtGui.QLabel('Title : ---')
self.summary = QtGui.QLabel('Summary : ---')
self.link = QtGui.QLabel('Link : ---')
self.layout.addWidget(self.title)
self.layout.addWidget(self.summary)
self.layout.addWidget(self.link)
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
window = MyWindow()
window.show()
sys.exit(app.exec_())
Inside the code, there are comments to help you understand why I did to build an organized GUI. There is also an example of a Signal being used to connect the action of itemDoubleClicked from the first widget to the second one. Here is how the MainWindow looks:
It is not very clear how the layouts work just from seeing the result, so I did a little paint over to a better understanding:
The blue box is the vertical layout (QVBoxLayout) and the red one is the horizontal layout (QHBoxLayout). Inside the blue layout, are located the red layout (above) and the exit button (below); and inside the red layout, are located the widget_1 (left) and the widget_2 (right).
Other Solution
An "easier" solution will be building the widgets inside the MainWindow instead of creating separate classes. With this you will avoid the use of signals, but the code will become a little more confusing because all the code will be cramped in one class.

The layout is incorrect after remove widget

I am implement my project using pyqt5. Currently, I have a window including many widget. Now, I want to remove some widgets. The window looks like:
Now, I want to remove the 'name1' widget including the QLabel and QPushButton.
However, after removing all 'name1' widgets, the 'name2' widgets including QLabel and QPushButton can not self-adapte with the window, like:
All my code is:
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
import sys
class Window(QDialog):
def __init__(self):
super().__init__()
self.initGUI()
self.show()
def initGUI(self):
layout = QVBoxLayout()
self.setLayout(layout)
removeLayout = QHBoxLayout()
self.__removeText = QLineEdit()
self.__removeBtn = QPushButton('Remove')
self.__removeBtn.clicked.connect(self.remove)
removeLayout.addWidget(self.__removeText)
removeLayout.addWidget(self.__removeBtn)
ROIsLayout = QVBoxLayout()
for name in ['name1', 'name2']:
subLayout = QHBoxLayout()
subText = QLabel(name)
subText.setObjectName(name)
subBtn = QPushButton(name)
subBtn.setObjectName(name)
subLayout.addWidget(subText)
subLayout.addWidget(subBtn)
ROIsLayout.addLayout(subLayout)
layout.addLayout(removeLayout)
layout.addLayout(ROIsLayout)
self.__ROIsLayout = ROIsLayout
def remove(self, checked=False):
name = self.__removeText.text()
while True:
child = self.__ROIsLayout.takeAt(0)
if child == None:
break
while True:
subChild = child.takeAt(0)
if subChild == None:
break
obName = subChild.widget().objectName()
if name == obName:
widget = subChild.widget()
widget.setParent(None)
child.removeWidget(widget)
self.__ROIsLayout.removeWidget(widget)
del widget
if __name__ == '__main__':
app = QApplication(sys.argv)
window = Window()
sys.exit(app.exec_())
update:
Actually, the issue may be the takeAt. The following code is workable:
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
import sys
class Window(QDialog):
def __init__(self):
super().__init__()
self.initGUI()
self.show()
def initGUI(self):
layout = QVBoxLayout()
self.setLayout(layout)
removeLayout = QHBoxLayout()
self.__removeText = QLineEdit()
self.__removeBtn = QPushButton('Remove')
self.__removeBtn.clicked.connect(self.remove)
removeLayout.addWidget(self.__removeText)
removeLayout.addWidget(self.__removeBtn)
ROIsLayout = QVBoxLayout()
for name in ['name1', 'name2']:
subLayout = QHBoxLayout()
subLayout.setObjectName(name)
subText = QLabel(name, parent=self)
subText.setObjectName(name)
subBtn = QPushButton(name, parent=self)
subBtn.setObjectName(name)
subLayout.addWidget(subText)
subLayout.addWidget(subBtn)
ROIsLayout.addLayout(subLayout)
print(name, subLayout, subText, subBtn)
layout.addLayout(removeLayout)
layout.addLayout(ROIsLayout)
self.__ROIsLayout = ROIsLayout
self.record = [subLayout, subText, subBtn]
def remove(self, checked=False):
layout = self.record[0]
txt = self.record[1]
btn = self.record[2]
layout.removeWidget(txt)
txt.setParent(None)
txt.deleteLater()
layout.removeWidget(btn)
btn.setParent(None)
btn.deleteLater()
if __name__ == '__main__':
app = QApplication(sys.argv)
window = Window()
sys.exit(app.exec_())
But, I have printed the QLabel/QPushButton in the self.record, and I find it is the same with that from child.takeAt(0).widget().
The main issue in your code is that you're constantly using takeAt(). The result is that all items in the __ROIsLayout layout will be removed from it (but not deleted), which, in your case, are the sub layouts. This is clearly not a good approach: only the widgets with the corresponding object name will be actually deleted, while the others will still be "owned" by their previous parent, will still be visible at their previous position and their geometries won't be updated since they're not managed by the layout anymore.
There are multiple solutions to your question, all depending on your needs.
If you need to remove rows from a layout, I'd consider setting the object name on the layout instead, and look for it using self.findChild().
Also consider that, while Qt allows setting the same object name for more than one object, that's not suggested.
Finally, while using del is normally enough, it's usually better to call deleteLater() for all Qt objects, which ensures that Qt correctly removes all objects (and related parentship/connections).
Another possibility, for this specific case, is to use a QFormLayout.

Displaying Gif Loading in PyQt4

I am trying to display a loading gif while other code executes. I am very unfamiliar with PyQt and have tried following the code at this link, which seems to be the standard way of executing a gif. I only want the gif playing and do not want a button. Here is the code I am currently at, but it is very poor.
self.movie = QMovie(coffeeloading.gif, self)
size = self.movie.scaledSize()
self.movie_screen.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
self.movie_screen.setAlignment(Qt.AlignCenter)
self.movie_screen = QLabel()
main_layout = QVBoxLayout()
main_layout.addWidget(self.movie_screen)
self.setLayout(main_layout)
self.movie.setCacheMode(QMovie.CacheAll)
self.movie.setSpeed(100)
self.movie_screen.setMovie(self.movie)
self.movie.start()
This is supposed to execute after a button press and fill up the whole screen of 240x320, but I dont have any idea how to do it. I have already read through many of the other stackoverflow and other links, but none of them seem to address how to complete this.
As an alternative, you can use this class here.
QtWaitingSpinner extends the QtWidgets.QWidget class and you can start your spinner by simply running
your_QtWaitingSpinnerObject.start()
You can check this answer as well.
# -*- coding: utf-8 -*-
import sys
from PySide.QtGui import *
from PySide.QtCore import *
class test_widget(QWidget):
m_play_state = False
def __init__(self):
super(test_widget, self).__init__()
self.__ui__()
def __ui__(self):
t_lay_parent = QVBoxLayout()
self.m_label_gif = QLabel()
self.m_button_play = QPushButton("Play")
t_lay_parent.addWidget(self.m_label_gif)
t_lay_parent.addWidget(self.m_button_play)
self.m_movie_gif = QMovie("loding.gif")
self.m_label_gif.setMovie(self.m_movie_gif)
self.m_label_gif.setScaledContents(True)
self.m_label_gif.hide()
self.setLayout(t_lay_parent)
self.m_button_play.clicked.connect(self.slt_play)
def slt_play(self):
if self.m_play_state:
self.m_label_gif.hide()
self.m_movie_gif.stop()
self.m_play_state = False
else:
self.m_label_gif.show()
self.m_movie_gif.start()
self.m_play_state = True
if __name__ == "__main__":
app = QApplication(sys.argv)
win = test_widget()
win.show()
sys.exit(app.exec_())

How can I add a submit, output and input box using PyQt4?

I never tried creating a GUI with a language other than Java(kinda left it aside not long ago)
and started using Python.
made a simple program that calculates Pi to a certain digit as the user wishes.
Now, I created a window with PyQt4, made a button and got everything in place.
How can I add a input box so that the user could enter a number into it, make the button "Enter" the information and at the end of all that output it to the window instead of the terminal?
That's what I've got for now:
import sys
from PyQt4 import QtGui
from PyQt4 import QtCore
from decimal import *
class Window(QtGui.QMainWindow):
def __init__(self):
super(Window, self).__init__()
self.setGeometry(50, 50, 800, 600)
self.setWindowTitle("Pi's Nth Digit")
self.setWindowIcon(QtGui.QIcon('icon.jpg'))
self.buttons()
def buttons(self):
btn = QtGui.QPushButton("Quit",self)
btn1 = QtGui.QPushButton("Get Pi",self)
btn.clicked.connect(QtCore.QCoreApplication.instance().quit)
btn1.clicked.connect(self.getpi())
btn1.resize(btn1.sizeHint())
btn.resize(btn.sizeHint())
btn1.move(350,500)
btn.move(450,500)
self.show()
def start():
app = QtGui.QApplication(sys.argv)
GUI = Window()
sys.exit(app.exec_())
start()
don't mind the getpi function.
Thanks! :)
You would want to use a QLineEdit or a QSpinBox for a number. If you want multiple things in a widget you would use a layout. A QMainWindow typically has one central widget and toolbars and dock widgets.
class Window(QtGui.QMainWindow):
def __init__(self):
super().__init__()
self.container = QtGui.QWidget()
self.setCentralWidget(self.container)
self.container_lay = QtGui.QVBoxLayout()
self.container.setLayout(self.container_lay)
# Input
self.le = QtGui.QLineEdit()
self.container_lay.addWidget(self.le)
# enter button
self.enter_btn = QtGui.QPushButton("Enter")
self.container_lay.addWidget(self.enter_btn)
self.enter_btn.clicked.connect(self.run) # No '()' on run you want to reference the method.
# display
self.container_lay.addWidget(QtGui.QLabel("Answer:"))
self.ans = QtGui.QLabel()
self.container_lay.addWidget(self.ans)
def run(self):
precision = self.le.text()
pi = str(round(math.pi, precision)) # probably different formatting
self.ans.setText(pi)
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
window = Window()
window.show()
sys.exit(app.exec_())
You have almost everything, just add a QLineEdit to get the input and a QLabel where to show the result (with QLabel.setText).

Categories