I try merge QgsMessageBar with ma ui file
from ui_file import Ui_File
class MyClass(QDialog):
def __init__(self):
QDialog.__init__(self)
self.bar = QgsMessageBar()
self.ui = Ui_File()
self.ui.setupUi(self)
self.ui.pushButton_2.clicked.connect(self.run)
def run(self):
self.bar.pushMessage("Hello", "World", level=QgsMessageBar.INFO)
When I change 'bar' to 'ui' I get error:
'Ui_File' object has no attribute 'pushMessage'
Something is missing in ui file?
How to fix it?
The code in your example looks fine as it is, but you need to add the message-bar to the layout of the dialog.
How you do this will depend on what kind of layout the dialog has, and where you want the message-bar to appear. If the layout is QVBoxLayout, and you want the message-bar at the bottom of the dialog, just do:
self.layout().addWidget(self.bar)
and to put it at the top of the dialog, you would do:
self.layout().insertWidget(0, self.bar)
However, if the layout is a QHBoxLayout or QGridLayout, you will probably have to alter things in Qt Designer to get things to work properly. In particular, QGridLayout has no method for inserting widgets, so you would have to leave a space for the message-bar if you want it at the top of the dialog. You may also need to ensure that the message-bar spans the full width of the dialog. See the docs for QGridLayout.addWidget for more details.
For a QHBoxLayout it's much easier - just put the existing layout inside a QVBoxLayout layout, and proceeed as above.
Related
The code below, which is based on an example from zetcode.com, creates a single combo box. There are several issues with the resulting dialog, but the following are especially annoying:
PyQt displays a vertical scrollbar for the combo box, although there is plenty of space to display the entire list of options without a scrollbar.
I've tried to move the combo box to a position near the upper-left corner of the window, but this isn't working.
#!/usr/bin/python
import sys
from PyQt5.QtWidgets import QWidget, QLabel, QHBoxLayout, QComboBox, QApplication
class Example(QWidget):
def __init__(self):
super().__init__()
self.setFixedWidth(400)
self.setFixedHeight(500)
self.initUI()
def initUI(self):
hbox = QHBoxLayout()
self.lbl = QLabel('Animals', self)
self.lbl.setStyleSheet('font-size:11pt')
combo = QComboBox(self)
combo.addItem('bear')
combo.addItem('cat')
combo.addItem('dog')
combo.addItem('dolphin')
combo.addItem('elephant')
combo.addItem('fish')
combo.addItem('frog')
combo.addItem('horse')
combo.addItem('rabbit')
combo.addItem('rat')
combo.addItem('shark')
combo.addItem('snake')
combo.addItem('tiger')
combo.addItem('whale')
combo.activated[str].connect(self.onActivated)
hbox.addWidget(combo)
hbox.setSpacing(20)
hbox.addWidget(self.lbl)
self.setContentsMargins(20, 20, 20, 20)
self.setLayout(hbox)
combo.move(20, 60)
self.setWindowTitle('QComboBox')
self.show()
def onActivated(self, text):
self.lbl.setText(text)
self.lbl.adjustSize()
def main():
app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
There are two wrong assumptions in the question.
the list of a QComboBox is a popup widget, it doesn't care (nor it should) about the available space the combobox might have: consider it as much as a context menu, which just pops out over the window, possibly going outside its boundaries if it requires more space (and that's just because those boundaries are meaningless to the menu);
the combo has been added to a layout manager, which takes care about resizing and positioning its (managed) child widgets, and that's why you cannot manually "move" them: the layout already sets the geometries automatically on its own everytime the widget is resized (which also happen when it's shown the first time), so any attempt to use move(), resize() or setGeometry() is completely useless;
When adding a widget to a layout, the default behavior is to make it occupy as much space as possible; since a QComboBox is one of those widgets that have a fixed size, the result is that it's actually centered (vertically and horizontally) in the space the layout is "assigning" to it, and this is clearly visible in your case because you set a fixed size for the container widget that is much bigger than what its contents would need.
There are two ways to align those widgets on top:
add the alignment arguments to addWidget:
hbox.addWidget(combo, alignment=QtCore.Qt.AlignTop)
hbox.addWidget(self.lbl, alignment=QtCore.Qt.AlignTop)
note that this won't give you good results in your case, because the label and the combo box have different heights, so the label might look "higher" than the combo;
use a QVBoxLayout layout as main layout for the widget, add the horizontal layout to it and then add a stretch after that (a stretch on a box layout is a "spacer" that tries to occupy as much space as possible)
# ...
mainLayout = QVBoxLayout()
mainLayout.addLayout(hbox)
mainLayout.addStretch()
self.setLayout(mainLayout)
PS: if you need to add lots of (string only) elements to a QComboBox, use addItems() instead of individually adding each of them.
I am trying to identify the object name of a pyqtgraph plotwidget I am mouse wheeling on. However, I can only seem to get the object id "PyQt5.QtWidgets.QWidget object at 0x0000018ED2ED74C8". If I use the QApplication.widgetAt(event.globalPos()).objectName I get nothing, even though I have set the object name. Can you help me?
Sample code:
# Import packages
from PyQt5.QtWidgets import QApplication, QWidget, QHBoxLayout
import pyqtgraph as pg
import sys
class MainWindow(QWidget):
def __init__(self):
super(MainWindow, self).__init__()
self.graphLayout = QHBoxLayout()
self.graph = pg.PlotWidget(name="graph1")
self.graph.setObjectName("graph1")
self.graphLayout.addWidget(self.graph)
self.setLayout(self.graphLayout)
def wheelEvent(self, event):
hoveredWidget = QApplication.widgetAt(event.globalPos())
print(hoveredWidget.objectName())
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = MainWindow()
ex.show()
sys.exit(app.exec_())
A PlotWidget is actually a subclass of QAbstractScrollArea, which is a complex widget that has at least three children widgets: the scroll bars (even when they're hidden) and, most importantly, the viewport, which actually is the "content" of the scroll area.
This means that using widgetAt() you are not getting the plot widget (the scroll area), but its viewport. In fact, in your case you can get the plot widget by checking the parent:
def wheelEvent(self, event):
hoveredWidget = QApplication.widgetAt(event.globalPos())
if hoveredWidget and hoveredWidget.parent():
print(hoveredWidget.parent().objectName())
Be careful when intercepting events from a parent widget, especially for widget as complex as scroll areas: it's not guaranteed that you will receive them, as the children could accept them, preventing further propagation to their parent(s).
If you need more control over them, it's usually better to implement the respective methods in their subclasses or installing an event filter on the instances.
Note that, for the reason above, if you want to filter events on a scroll area you might prefer to install the filter on the viewport:
self.graph.viewport().installEventFilter(self)
I need to show a QWidget, which code is written in another module, when a certain button is pressed. To accomplish this, I wrote this code:
class Window(QMainWindow):
def __init__(self):
QMainWindow.__init__(self)
#A lot of stuff in here
#The button is connected to the method called Serial_connection
self.connect(self.btn_selection_tool3, SIGNAL("clicked()"), self.Serial_connection)
def Serial_connection(self):
LiveData.LiveData(self).show()
Doing this, I open a QWidget and it works fine. But, when I want to close this QWidget, I can not do it. This is the code of the QWidget:
class LiveData(QWidget):
def __init__(self,parent = None):
super(QWidget, self).__init__(parent)
#Another stuff in here
#I create a "close" button connected to another method
self.connect(self.closeBtn, QtCore.SIGNAL("clicked()"), self.StopAndClose)
def StopAndClose(self):
print "Closing window"
self.close() #HERE IS WHERE I HAVE THE PROBLEM
I´ve tried several options like: self.close(), self.accept() or even sys.exit(1). The problem with the latter sys.exit(1) is that it closes the QWidget and the QMainWindow. So, how can I close this QWidget only? Hope you can help me.
You probably want your QWidget to be a QDialog. If it's a temporary modal widget, you should be calling the dialog like this
dialog = LiveData.LiveData(self)
dialog.exec_()
If you just want to show the dialog at the same time as your main window, and users are meant to interact with both (though from a design perspective, this doesn't sound like a great idea), you can continue to use .show()
Also, you should use the new-style signal/slot syntax. The old syntax hasn't been used for many years.
self.closeButton.clicked.connect(self.StopAndClose)
Though, for a QDialog you can just do
self.closeButton.clicked.connect(self.accept)
I am building a Gui in QtDesigner but i do not understand how i add a "dynamical property":
I try to add a QTable Widget but the Header of the Columns are to large (The Text is just 2 letter in the Columns).
For Space reasons in my Gui i just need them to be as big as the text is (or let us say 4 letters)
i found the
QHeaderView::ResizeToContents method but i do not know how to use it- is there a way to do this in QtDesigner?
I am new to this and i do not know how to change the code behind the Gui...
For PyQt, the main purpose of Qt Designer is to create the main GUI structure of your application. It only allows a subset of the available properties to be modified for any given widget, and it cannot be used to write the application's main logic.
Instead, the idea is to generate a python module from the ui file created by Qt Designer, and then import it into your application where you can do the remaining setup code, connect signals, write all the event handlers, etc.
Let's say you've created a ui file with Qt Designer and named it mainwindow.ui.
You would then generate the python module like this:
pyuic4 -o mainwindow_ui.py mainwindow.ui
Next, you would write a separate main.py script that imports the GUI classes from the generated module, and creates instances of them as needed.
So your main.py would look something like this:
from PyQt4 import QtCore, QtGui
from mainwindow_ui import Ui_MainWindow
class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
def __init__(self, parent=None):
QtGui.QMainWindow.__init__(self, parent)
self.setupUi(self)
header = self.tableWidget.horizontalHeader()
header.setResizeMode(QtGui.QHeaderView.ResizeToContents)
...
if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
The base-class here must be same as the top-level widget in Qt Designer (i.e. usually either QMainWindow, QDialog, or QWidget). Also, the objectName property of the top-level widget is used to generate the classname of the imported GUI class (with "Ui_" prepended to it). The example above assumes this was set to "MainWindow".
The objectName properties of all the other widgets will become attributes of the MainWindow class, so that they can be accessed easily in the rest of your code. Because of this, it's important that you always set the objectName properties to descriptive names (i.e. not "pushButton_1", "pushButton_2", etc).
This is driving me a little crazy. Hope someone can clear this up for me. Running the following code results in the first print statement being a list with one element the QVBoxLayout object. I set two objects to layout why do I get only one?
The second print statement gives two objects the QHBoxLayout and QPushButton. Isn't QPushButton a child of layout?
I would expect layout.children() to give me two objects QPushButton and QVBoxLayout
and self.children() to give me one object QHBoxLayout. What am I missing?
from PySide.QtGui import *
import sys
class Main(QWidget):
def __init__(self, parent=None):
super(Main, self).__init__(parent)
layout = QHBoxLayout(self)
layout.addWidget(QPushButton("foo"))
layout.addLayout(QVBoxLayout())
print layout.children()
print self.children()
app = QApplication([])
main = Main()
main.show()
sys.exit(app.exec_())
I guess the note from the documentation explains this clearly enough:
Note: Widgets in a layout are children of the widget on which the
layout is installed, not of the layout itself. Widgets can only have
other widgets as parent, not layouts.