I would like to put a navigation toolbar inside a widget I created with Qt designer.
I have a GUI, made in QT designer, that has 10 tabs. Each tab has a widget that I promoted to canvas.
I would like to put a navigation toolbar inside each widget.
Up to now I have tried this.
But this code simply adds a navigation toolbar at the top of the GUI
import woop
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg
from matplotlib.backends.backend_qt4agg import NavigationToolbar2QT as NavigationToolbar
from PyQt4 import Qt, QtCore,QtGui
from matplotlib import cm
from matplotlib.figure import Figure
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg
from matplotlib.backends.backend_qt4agg import NavigationToolbar2QT as NavigationToolbar
import os
class woop(QtGui.QMainWindow, woop.Ui_MainWindow):
"""
Main control function for Woop GUI.
"""
# ----------------------------
def __init__(self, parent=None):
"""
Setup the GUI, and connect the buttons to functions.
"""
import os
super(woop, self).__init__(parent)
self.setupUi(self)
toolBar1 = NavigationToolbar(self.widget_LID1, self)
toolBar2 = NavigationToolbar(self.widget_LID2, self)
toolBar3 = NavigationToolbar(self.widget_LID3, self)
toolBar4 = NavigationToolbar(self.widget_LID4, self)
toolBar5 = NavigationToolbar(self.widget_LID5, self)
toolBar6 = NavigationToolbar(self.widget_LID6, self)
toolBar7 = NavigationToolbar(self.widget_LID7, self)
toolBar8 = NavigationToolbar(self.widget_LID8, self)
toolBarALL = NavigationToolbar(self.widget_LID_ALL, self)
toolBarMIR = NavigationToolbar(self.widget_MIR, self)
self.addToolBar(toolBar1)
self.addToolBar(toolBar2)
self.addToolBar(toolBar3)
self.addToolBar(toolBar4)
self.addToolBar(toolBar5)
self.addToolBar(toolBar6)
self.addToolBar(toolBar7)
self.addToolBar(toolBar8)
self.addToolBar(toolBarALL)
self.addToolBar(toolBarMIR)
self.widget_LID1.figure.clear()
self.widget_LID1.draw()
self.widget_LID2.figure.clear()
self.widget_LID2.draw()
self.widget_LID3.figure.clear()
self.widget_LID3.draw()
self.widget_LID4.figure.clear()
self.widget_LID4.draw()
self.widget_LID5.figure.clear()
self.widget_LID5.draw()
self.widget_LID6.figure.clear()
self.widget_LID6.draw()
self.widget_LID7.figure.clear()
self.widget_LID7.draw()
self.widget_LID8.figure.clear()
self.widget_LID8.draw()
self.widget_LID_ALL.figure.clear()
self.widget_LID_ALL.draw()
self.widget_LID_14.figure.clear()
self.widget_LID_14.draw()
self.widget_LID_58.figure.clear()
self.widget_LID_58.draw()
self.widget_MIR.figure.clear()
self.widget_MIR.draw()
def main():
"""
Main function
the only input to the GUI is the debug
by default is set to INFO
"""
import sys
app = QtGui.QApplication(sys.argv)
MainWindow = woop()
#MainWindow.show()
MainWindow.showMaximized()
app.exec_()
if __name__ == '__main__':
main()
Try to add each toolbar directly to the corresponding widget using a QVBoxLayout as described in How to embed matplotlib in pyqt - for Dummies.
Or, if you still prefer to use the toolbar area of the QMainWindow, you need to connect the currentChanged signal of the QTabWidget to a slot replacing the toolbar by the one corresponding to the widget of the selected widget.
I managed to solve in this way.
I created this function
def _initialize_widget(self,widget):
"""
function that:
- initialises every tab (widget)
- add layout
- add navigation toolbar and position it at the bottom of the tab
:param widget:
:return:
"""
widget.figure.clear()
widget.draw()
widget.setLayout(QtGui.QVBoxLayout())
widget.layout().setContentsMargins(0, 710, 50, -0)#(left, top, right, bottom)
widget.layout().setSpacing(0)
toolbar = NavigationToolbar(widget, self)
widget.layout().addWidget(toolbar)
widget.figure.clear()
widget.draw()
and then I initialize the widgets (canvas)
self._initialize_widget(self.widget_LID1)
In this way I add a navigation toolbar at the bottom of the canvas.
Related
I have embedded a matplotlib figure in a pyqt5 window along with the toolbar, this is my code:
from matplotlib.backends.backend_qt5agg import NavigationToolbar2QT as NavigationToolbar
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.figure import Figure
from PyQt5 import QtWidgets
class PlotWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super(PlotWindow, self).__init__(parent=parent)
self.figure = Figure(tight_layout=True)
self.canvas = FigureCanvas(self.figure)
self.setCentralWidget(self.canvas)
self.toolbar = NavigationToolbar(self.canvas, self)
self.addToolBar(self.toolbar)
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
mw = PlotWindow()
ax = mw.figure.add_subplot()
mw.show()
exit(app.exec_())
And this is what it looks like:
I can drag the toolbar to the bottom and dock it there:
But I can't dock it to the side (left or right).
This is something you can do with any other standard pyqt5 toolbar, why does it not work with the matplotlib toolbar? and how do I make it work?
I can do it in code by changing this line:
# self.addToolBar(self.toolbar)
self.addToolBar(QtCore.Qt.LeftToolBarArea, self.toolbar)
The result is:
Which is what I'm after, but if I then undock the toolbar from the left side I can no longer dock it there again and can only dock it in top and at the bottom.
The QToolBar provided by matplotlib is configured to only allow dragging on the top and information as seen in the source code:
self.setAllowedAreas(QtCore.Qt.ToolBarArea(
_to_int(_enum("QtCore.Qt.ToolBarArea").TopToolBarArea) |
_to_int(_enum("QtCore.Qt.ToolBarArea").BottomToolBarArea)))
The solution is to establish all areas:
self.toolbar.setAllowedAreas(QtCore.Qt.ToolBarArea.AllToolBarAreas)
When I made a GUI i used different classes to construct the main UI Screen.
My code has the following structure:
This is the GUI itself:
The bottum_buttons.py creates the 3 buttons at the buttom. This is the code that is inside bottum_buttons.py:
import Advanced_window
from PyQt5 import QtCore
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from datetime import datetime
import calendar
import sys
class bottum_buttons(QWidget):
def __init__(self):
QWidget.__init__(self)
# Create Layout
self.bottum_box = QHBoxLayout()
# Creating Buttons
self.cancel_button = QPushButton("Cancel")
self.run_button = QPushButton("Run")
self.advanced_button = QPushButton("Advancend Options")
self.add_items_to_layout()
self.create_button_functions()
def add_items_to_layout(self):
self.bottum_box.addWidget(self.cancel_button)
self.bottum_box.addWidget(self.run_button)
self.bottum_box.addWidget(self.advanced_button)
def create_button_functions(self):
self.cancel_button.clicked.connect(self.close)
self.advanced_button.clicked.connect(Advanced_window.advancedwindows)
def return_bottum_buttons(self):
return self.bottum_box
My code that actually constructs the GUI is inside main_screen.py.
The following code is inside this file:
from Ui_Elements import option_box
from Ui_Elements import path_box
from Ui_Elements import bottum_buttons
from Ui_Elements import command_output
from PyQt5 import QtCore
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from datetime import datetime
import calendar
import sys
class main_screen(QDialog):
def __init__(self):
QDialog.__init__(self)
self.setWindowTitle("Robo Tool")
self.main_frame = QVBoxLayout()
# Get UI Elements
path_ui = path_box.path_box()
option_ui = option_box.option_box()
command_ui = command_output.command_box()
bottum_ui = bottum_buttons.bottum_buttons()
self.path = path_ui.return_path_box()
self.option_box = option_ui.return_options_box()
self.command_output = command_ui.return_command_box()
self.bottum_buttons = bottum_ui.return_bottum_buttons()
self.setLayout(self.add_item_to_frame(self.main_frame))
def add_item_to_frame(self, main_frame):
main_frame.addLayout(self.path)
main_frame.addLayout(self.option_box)
main_frame.addLayout(self.command_output)
main_frame.addLayout(self.bottum_buttons)
return main_frame
app = QApplication(sys.argv)
dialog = main_screen()
dialog.show()
app.exec_()
Now the problem is. When i start the main_screen.py the GUI shows up as the picture provided. But the buttons don't work. I dont get any error message. They're still clickable but they dont run the command i provided. Can somebody please help me out.
I don't know what Advanced_window.advancedwindows() is supposed to do, but your cancel button is connected to bottom_buttons.close, not to main_screen.close which I assume is what you want. Since bottom_buttons has no knowledge in advance about which window is supposed to be closed, you can't really connect the button to the close method of a predefined widget. What you could do however is to use self.window().close() instead which would close the next-level ancestor widget of bottom_buttons that has a window. For this, you would need to set the layout of bottom_bottuns to self.bottom_box and add the whole widget to the layout of main_screen rather than just the layout.
This would mean that you would get something like this for bottom_buttons:
class bottum_buttons(QWidget):
def __init__(self):
.... as before ....
# set bottom_box as layout of self
self.setLayout(self.bottom_box)
....
def create_button_functions(self):
# connect cancel button to close method of top level ancestor widget
self.cancel_button.clicked.connect(lambda: self.window().close())
....
And for main_screen:
class main_screen(QDialog):
def __init__(self):
.... as before ....
# set self.bottom_buttons to bottom_buttons widget rather than the layout
self.bottum_buttons = bottum_ui
self.setLayout(self.add_item_to_frame(self.main_frame))
def add_item_to_frame(self, main_frame):
...
# add bottom_buttons widget to the layout.
main_frame.addWidget(self.bottum_bottons)
return main_frame
I am new to Qt and PyQt and I appreciate it if someone can help me with this. I am trying to add a leaflet map to a GUI that I am creating using Qt designer and Python. Since there is no such widget, I create a simple Widget in the Qt Designer and promote it to a "LeafWidget" as shown below:
I save this file as (user_interface.ui) and then in my index.py file (under the same folder), I use the class leafWidget (with the same name as what defined in the Qt Designer) to define this new widget. I'm not sure if it is right or not. My "index.py" file that I run is as below.
import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from pyqtlet import L, MapWidget
from PyQt5.uic import loadUiType
ui,_=loadUiType('user_interface.ui')
class LeafWidget (QWidget):
def __init__(self):
QWidget.__init__(self)
self.mapWidget = MapWidget()
self.map = L.map(self.mapWidget)
self.map.setView([39.764075, -86.159019], 10)
L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png').addTo(self.map)
self.layout = QVBoxLayout(self)
self.layout.addWidget(self.mapWidget)
self.show()
class MainApp(QMainWindow, ui):
def __init__(self):
QMainWindow.__init__(self)
self.setupUi(self)
self.mainWindow_tabWidget.setCurrentIndex(1)
def main():
app=QApplication(sys.argv)
window = MainApp()
window.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
When I run it, it does open up the window, but the place for the map widget is empty as you see below. Am I defining this class correctly? In my MainApp class, do I need to add this new custom widget somehow? I don't get any specific errors in my debug console, So I'm not sure what I am missing.
I am trying to muddle my way through embedding a matplotlib figure inside of a Qt GUI created using Qt Designer. I am already able to create the figure I want just through Python. I've created a basic GUI with widgets to allow me to select/load input files, and plot the data in those files in a matplotlib figure that is embedded in the GUI. I accomplish this by adding a blank widget to the GUI called plotwidget, and then calling the GraphInit class with this widget as input.
The problem I am currently facing is that while my plot shows up and updates as desired inside the GUI, it doesn't seem to pay attention to the size policy defined for it in either my Python code (where the FigureCanvas is created) or for the plotWidget widget in Qt Designer. I have been using this demo, among others, as a starting point for this project. However, all of these examples have generated the GUI entirely from within Python. I suspect I am doing something wrong in assigning the matplotlib figure to the widget, but I haven't been able to figure out what.
Code (import & plotting code removed, but the core where figure is added is there):
import sys
import os
import matplotlib
matplotlib.use('Qt5Agg')
from PyQt5 import QtCore, QtGui
from PyQt5.QtWidgets import QApplication, QMessageBox, QFileDialog, QPushButton, QLabel, QRadioButton, QDoubleSpinBox, QSpinBox, QWidget, QSizePolicy, QMainWindow
import PyQt5.uic
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.figure import Figure
import json
from datetime import datetime
import numpy as np
class LogViewer(QApplication):
def __init__(self):
QApplication.__init__(self, sys.argv)
self.ui = UI()
#staticmethod
def main():
vwr = LogViewer()
vwr.run()
def run(self):
self.ui.win.show() # Show the UI
self.ui.run() # Execute the UI run script
self.exec_()
class Graph_init(FigureCanvas):
def __init__(self, parent=None):
fig = Figure()
self.axes = fig.add_subplot(111)
self.compute_initial_figure()
self.axes.grid()
FigureCanvas.__init__(self, fig)
self.setParent(parent)
FigureCanvas.setSizePolicy(self, QSizePolicy.Expanding, QSizePolicy.Expanding)
FigureCanvas.updateGeometry(self)
def compute_initial_figure(self):
pass
class UI(object):
def __init__(self):
ui_path = os.path.dirname(os.path.realpath(__file__))
self.win = PyQt5.uic.loadUi(ui_path + '\\logview.ui')
self.filename = ui_path + '\\test.txt'
self.plotWin = Graph_init(self.win.plotWidget)
def run(self):
self.init_ui() # get initial values from the controllers
self.attach_ui_connections()
def init_ui(self):
w = self.win
w.txtLogFilename.setText(self.filename.split('/')[-1]) # just the file (no path)
def attach_ui_connections(self):
w = self.win
if __name__ == '__main__':
LogViewer.main()
GUI is available here. Any suggestions appreciated!
I checked your ui file and plotWidget has no layout at all. Try to give it one, I suggest a grid layout.
Then, after parenting the canvas
self.setParent(parent)
try adding it to the parent layout:
parent.layout().addWidget(self)
I want to do hover. I saw an example and then write a script which will be use as I made program. I am facing one problem that hover only occur if you put mouse on the left corner of button. I want that it will happen for all the button that if i move cursor on button then it should change.
Here is my code:
from PyQt4 import QtGui, QtCore
from PyQt4.QtCore import pyqtSignal
import os,sys
class HoverButton(QtGui.QToolButton):
def enterEvent(self,event):
print("Enter")
button.setStyleSheet("background-color:#45b545;")
def leaveEvent(self,event):
button.setStyleSheet("background-color:yellow;")
print("Leave")
app = QtGui.QApplication(sys.argv)
widget = QtGui.QWidget()
button = QtGui.QToolButton(widget)
button.setMouseTracking(True)
buttonss = HoverButton(button)
button.setIconSize(QtCore.QSize(200,200))
widget.show()
sys.exit(app.exec_())
Is this what you're looking for
from PyQt4 import QtGui, QtCore
from PyQt4.QtCore import pyqtSignal
import os,sys
class Main(QtGui.QWidget):
def __init__(self, parent=None):
super(Main, self).__init__(parent)
layout = QtGui.QVBoxLayout(self) # layout of main widget
button = HoverButton(self)
button.setIconSize(QtCore.QSize(200,200))
layout.addWidget(button) # set your button to the widgets layout
# this will size the button nicely
class HoverButton(QtGui.QToolButton):
def __init__(self, parent=None):
super(HoverButton, self).__init__(parent)
self.setMouseTracking(True)
def enterEvent(self,event):
print("Enter")
self.setStyleSheet("background-color:#45b545;")
def leaveEvent(self,event):
self.setStyleSheet("background-color:yellow;")
print("Leave")
app = QtGui.QApplication(sys.argv)
main = Main()
main.show()
sys.exit(app.exec_())
In your code you had a button in a button and the nested button wasn't assigned to a QLayout widget. Although, I'm not sure why you're adding a button inside of a button. One thing that I've learned from working with GUI's is that it's so much easier if you modularize your code. Now you can take this custom button and apply it somewhere else.
You should use the stylesheet as
QToolButton:hover
{
background-color: rgb(175,175,175);
}
You probably want focus and blur, rather than enter and leave will only fire when the mouse actually enters or leaves the boundary of the button and will probably just be short duration impulses rather than toggles. focus and blur will toggle with the hover.