it's a little complicated but I will try
I have a panel or a button 'file' for the choice of a file and the opening of this file is a .nc file (netCDF4) so I would like to visualize it but the problem I would like to see it in one other panel which will be like a quicklook, and each time you have to choose a file of type .nc or directly to be visualized on the other panel
and here is part of my code for 2 panels:
class LeftPanelTop(wx.Panel): # panel choose file
def __init__(self, parent):
super().__init__(parent,style = wx.SUNKEN_BORDER)
self.SetBackgroundColour('snow2')
List_choices = ["1Km","3Km"]
List2 = ["3X3","5X5","7X7"]
self.dateLbl = wx.StaticBox(self, -1, 'Outils ', size=(310, 320))
self.dategraphSizer = wx.StaticBoxSizer(self.dateLbl, wx.VERTICAL)
combobox1 = wx.ComboBox(self,choices = List_choices, size =(80,20),pos =(180,50))
combobox2 = wx.ComboBox(self,choices = List2, size =(80,20),pos =(180,90))
wx.StaticText(self, label='Referen:', pos=(70, 50))
wx.StaticText(self, label='pixel:', pos=(70, 90))
QuickLook = wx.Button(self ,-1, "Open file" , size =(80, 25),pos =(180,130))
wx.StaticText(self, label='QuickLook:', pos=(70, 130))
QuickLook.Bind(wx.EVT_BUTTON, self.onOpen)
def onOpen(self, event):
wildcard = "netCDF4 files (*.nc)|*.nc"
dialog = wx.FileDialog(self, "Open netCDF4 Files| HDF5 files", wildcard=wildcard,
style=wx.FD_OPEN | wx.FD_FILE_MUST_EXIST)
if dialog.ShowModal() == wx.ID_CANCEL:
return
path = dialog.GetPath()
# panel for visualization
class LeftPanelBottom(wx.Panel):
def __init__(self, parent):
super().__init__(parent,style = wx.SUNKEN_BORDER)
self.SetBackgroundColour('whitesmoke')
self.dateLbl = wx.StaticBox(self, -1, 'QuickLook', size=(310, 600))
that it code for read and view netcdf4 in python3.6:
import numpy as np
import netCDF4
import matplotlib.pyplot as plt
#read the netcdf
fic='g_xvxvxvxv_20190108T120000Z.nc'
path='/home/globe/2019/01/08/'
nc = netCDF4.Dataset(path+fic,'r')
#read one variable in netcfd file
cm=nc.variables['cm'][:]
#visualization
plt.pcolormesh(cm)
plt.colorbar()
plt.show()
that what i would see in panel2 like quicklook:
[![enter image description here][1]][1]
what i would like to do is use my code to read the .nc in my code and that my users can just choose a file and then display automatically on the other panel2 :
[![enter image description here][2]][2]
maybe is like this example : How to use matplotlib blitting to add matplot.patches to an matplotlib plot in wxPython?
thank you for the help
Just open another frame and pass it the filename to be decoded, uncompressed, whatever, to be displayed.
The other option is to use webbrowser which will automatically pick the program required to display the file, based on the preferences that you have set on your pc.
import wx
import webbrowser
import numpy as np
from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas
from matplotlib.figure import Figure
class MyFrame(wx.Frame):
def __init__(self, *args, **kwargs):
wx.Frame.__init__(self, *args, **kwargs)
panel = wx.Panel(self)
sizer = wx.BoxSizer(wx.HORIZONTAL)
self.select_button = wx.Button(panel, label="Select file")
sizer.Add(self.select_button, 0, 0, 0)
self.select_button.Bind(wx.EVT_BUTTON, self.pick_file)
self.load_options = "netCDF4 files (nc)|*.nc| Text files (txt) |*.txt| All files |*.*"
panel.SetSizer(sizer)
def pick_file(self, event):
with wx.FileDialog(self, "Pick files", wildcard=self.load_options,
style=wx.FD_OPEN | wx.FD_FILE_MUST_EXIST | wx.FD_MULTIPLE) as fileDialog:
if fileDialog.ShowModal() != wx.ID_CANCEL:
chosen_file = fileDialog.GetPath()
if chosen_file.endswith('.txt'):
#Method 1 using another frame
QuickLook(parent=self, text=chosen_file)
elif chosen_file.endswith('.nc'):
QuickLook_plot(parent=self, text=chosen_file)
else:
#Method 2 (the smart method) using webbrowser which chooses the application
# to use to display the file, based on preferences on your machine
webbrowser.open_new(chosen_file)
class QuickLook(wx.Frame):
def __init__(self,parent,text=None):
wx.Frame.__init__(self, parent, wx.ID_ANY, "Quick Look", size=(610,510))
panel = wx.Panel(self, wx.ID_ANY, size=(600,500))
log = wx.TextCtrl(panel, wx.ID_ANY,size=(600,480),
style = wx.TE_MULTILINE|wx.TE_READONLY|wx.VSCROLL)
Quit_button = wx.Button(panel, wx.ID_ANY, "&Quit")
Quit_button.Bind(wx.EVT_BUTTON, self.OnQuit)
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(log, 1, wx.ALL|wx.EXPAND, 0)
sizer.Add(Quit_button,0,wx.ALIGN_RIGHT)
panel.SetSizerAndFit(sizer)
# use whatever method is appropriate for the file type
# to read, decode, uncompress, etc at this point
# I am assuming a text file below.
try:
with open(text,'rt') as f:
TextInfo = f.read()
log.write(TextInfo)
log.SetInsertionPoint(0)
self.Show()
except:
self.OnQuit(None)
def OnQuit(self,event):
self.Close()
self.Destroy()
class QuickLook_plot(wx.Frame):
def __init__(self, parent,text=None):
wx.Frame.__init__(self, parent, wx.ID_ANY, "Quick Plot", size=(610,510))
panel = wx.Panel(self, wx.ID_ANY, size=(600,500))
self.figure = Figure()
self.axes = self.figure.add_subplot(111)
self.canvas = FigureCanvas(panel, -1, self.figure)
Quit_button = wx.Button(panel, wx.ID_ANY, "&Quit")
Quit_button.Bind(wx.EVT_BUTTON, self.OnQuit)
self.sizer = wx.BoxSizer(wx.VERTICAL)
self.sizer.Add(self.canvas, 1, wx.LEFT | wx.TOP | wx.GROW)
self.sizer.Add(Quit_button, 0,wx.ALIGN_RIGHT)
panel.SetSizerAndFit(self.sizer)
#plot figure
t = np.arange(0.0, 30.0, 0.01)
s = np.sin(2 * np.pi * t)
self.axes.plot(t, s)
self.Show()
def OnQuit(self,event):
self.Close()
self.Destroy()
class MyApp(wx.App):
def OnInit(self):
frame = MyFrame(None, -1, 'A test dialog')
frame.Show()
return True
if __name__ == "__main__":
app = MyApp()
app.MainLoop()
Related
I would need add calendar to my small utility. I have a hello world code like this:
import wx
import wx.stc as stc
import wx.adv as adv
class MyFrame(wx.Frame):
def __init__(self):
super().__init__(parent=None, title='My fancy form app with calendar')
panel = wx.Panel(self)
my_sizer = wx.BoxSizer(wx.VERTICAL)
self.SetMinSize(wx.Size(400,450))
# Headline Text
self.headline_text = wx.StaticText(panel, style = wx.TE_CENTER & ~wx.TE_LEFT & ~wx.TE_RIGHT, label="This text will be placed to the top of my form")
my_sizer.Add(self.headline_text, 0, wx.ALL | wx.EXPAND, 5)
# Calendar under the text
self.cal = adv.CalendarCtrl(self, 10, wx.DateTime.Now())
my_sizer.Add(self.cal, 0, wx.ALL | wx.CENTER, 5)
if __name__ == '__main__':
app = wx.App()
frame = MyFrame()
app.MainLoop()
Without the block of code with Calendar, this works well. BoxSizer can arrange buttons, text labels, tables etc. - But the calendar kills the sizer and everything is in the top left corner.
So please, what is the proper usage of CalendarCtrl object? Thanks!
You were placing the calendar on the frame
self.cal = adv.CalendarCtrl(self ...
and the text on the panel
self.headline_text = wx.StaticText(panel ...
all widgets should really go on panels.
I have also moved all of your widgets to a panel class which helps with separation of concerns
import wx
import wx.stc as stc
import wx.adv as adv
class MyFrame(wx.Frame):
def __init__(self):
super().__init__(parent=None, title='My fancy form app with calendar')
panel = wx.Panel(self)
self.SetMinSize(wx.Size(400,450))
self.panel = MainPanel(self)
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(self.panel)
self.SetSizer(sizer)
self.Center()
self.Show()
class MainPanel(wx.Panel):
"""Create a panel class to contain screen widgets."""
def __init__(self, parent, *args, **kwargs):
super().__init__(parent, *args, **kwargs)
sizer = wx.BoxSizer(wx.VERTICAL)
# Headline Text
self.headline_text = wx.StaticText(self, style = wx.TE_CENTER & ~wx.TE_LEFT & ~wx.TE_RIGHT, label="This text will be placed to the top of my form")
sizer.Add(self.headline_text, 0, wx.ALL | wx.EXPAND, 5)
# Calendar under the text
self.cal = adv.CalendarCtrl(self, 10, wx.DateTime.Now())
sizer.Add(self.cal, 0, wx.ALL | wx.CENTER, 5)
self.SetSizer(sizer)
if __name__ == '__main__':
app = wx.App()
frame = MyFrame()
app.MainLoop()
I'm trying to make a sort of image viewer in which I put a background image ("Affichage du mur" button) and then I load images with the "Importer l'oeuvre" button (you can load as many images you want). It works fine but I would like that we could delete the images ... in fact I would like the image that we delete is the image selected by the user. I can't get the selected image to be deleted with the "Suppression de l'oeuvre" button ... it seems that there is a selectedItems() method but I don't know how to use it in my code. Can you help me please ? Here is a very simplified code of what I am doing :
import os, sys
try : import Image
except ImportError : from PIL import Image
# Imports PyQt5 -----------------------------------------------------------------------
from PyQt5.QtWidgets import QPushButton, QGridLayout, QGraphicsScene, QGraphicsView, \
QGraphicsPixmapItem, QGraphicsItem, QApplication, \
QMainWindow, QFileDialog, QWidget
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QPixmap, QColor, QTransform
# --------------------------------------------------------------------------------------
class TEST(QMainWindow):
def __init__(self):
super(TEST, self).__init__()
self.setWindowTitle('TEST')
self.setGeometry(10, 20, 1280, 760)
self.setMinimumSize(1280, 760)
# ----------------------------------------
self.graphe_vue = MonGraphiqueVueMur()
# ----------------------------------------
bout_visio_mur = QPushButton("Affichage du mur")
bout_visio_mur.setMaximumWidth(230)
bout_visio_mur.setMinimumWidth(230)
bout_visio_oeuvre = QPushButton("Importer l'oeuvre")
bout_visio_oeuvre.setMaximumWidth(230)
bout_visio_oeuvre.setMinimumWidth(230)
bout_supprimer_oeuvre = QPushButton("Suppression de l'oeuvre")
bout_supprimer_oeuvre.setMaximumWidth(230)
bout_supprimer_oeuvre.setMinimumWidth(230)
# ------------------------------------------------------------
bout_visio_mur.clicked.connect(self.graphe_vue.afficher_mur)
bout_visio_oeuvre.clicked.connect(self.graphe_vue.afficher_image_oeuvre)
bout_supprimer_oeuvre.clicked.connect(self.graphe_vue.supprimer_image_oeuvre)
# ------------------------------------------------------------
grid = QGridLayout()
grid.addWidget(self.graphe_vue, 0, 0)
grid.addWidget(bout_visio_mur, 1, 0)
grid.addWidget(bout_visio_oeuvre, 2, 0)
grid.addWidget(bout_supprimer_oeuvre, 3, 0)
widget = QWidget()
widget.setLayout(grid)
self.setCentralWidget(widget)
class MaScene(QGraphicsScene) :
def __init__(self, parent=None) :
super(MaScene, self).__init__(parent)
class MonGraphiquePixmapItemMur(QGraphicsPixmapItem) :
def __init__(self, parent=None):
super(MonGraphiquePixmapItemMur, self).__init__(parent)
class MonGraphiquePixmapItemOeuvre(QGraphicsPixmapItem) :
def __init__(self, parent=None):
super(MonGraphiquePixmapItemOeuvre, self).__init__(parent)
self.setFlag(QGraphicsItem.ItemIsMovable, True)
self.setFlag(QGraphicsItem.ItemIsSelectable, True)
self.setFlag(QGraphicsItem.ItemIsFocusable, True)
self.setAcceptHoverEvents(True)
def hoverEnterEvent(self, event):
print('setAcceptHoverEvents --> Position', event.pos(), type(event.pos()), type(event.pos().x()), type(event.pos().x()))
print("Position X", event.pos().x(), "Position Y", event.pos().y())
class MonGraphiqueVueMur(QGraphicsView) :
backgroundcolor = QColor(100, 100, 100)
def __init__(self, parent=None) :
super(MonGraphiqueVueMur, self).__init__(parent)
self.setBackgroundBrush(self.backgroundcolor)
self.scene = MaScene()
self.setScene(self.scene)
def wheelEvent(self, event):
zoomInFactor = 1.1
zoomOutFactor = 1 / zoomInFactor
self.setTransformationAnchor(QGraphicsView.NoAnchor)
self.setResizeAnchor(QGraphicsView.NoAnchor)
oldPos = self.mapToScene(event.pos())
if event.angleDelta().y() > 0:
zoomFactor = zoomInFactor
else:
zoomFactor = zoomOutFactor
self.scale(zoomFactor, zoomFactor)
newPos = self.mapToScene(event.pos())
delta = newPos - oldPos
self.translate(delta.x(), delta.y())
def afficher_mur(self) :
ouv = QFileDialog.getOpenFileName(self, 'Ouvrir une image', os.path.expanduser('~'), 'Images (*.jpg *.jpeg *.JPG *.JPEG *.png *.gif)')[0]
chemin_fichier = str(ouv)
img_mur = Image.open(chemin_fichier)
self.scene.clear()
self.items().clear()
largeur, hauteur = img_mur.size
pixmap = QPixmap(chemin_fichier)
item = MonGraphiquePixmapItemMur(pixmap)
item.setTransformationMode(Qt.SmoothTransformation)
self.scene.addItem(item)
self.setScene(self.scene)
self.fitInView(item, Qt.KeepAspectRatio)
x, y = 0, 0
self.setSceneRect(-x, -y, largeur, hauteur)
self.centerOn(10, 10)
self.show()
def afficher_image_oeuvre(self) :
ouv = QFileDialog.getOpenFileName(self, 'Ouvrir une image', os.path.expanduser('~'), 'Images (*.jpg *.jpeg *.JPG *.JPEG *.png *.gif)')[0]
chemin_fichier = str(ouv)
pixmap = QPixmap(chemin_fichier)
pixmap = pixmap.scaled(700, 700, Qt.KeepAspectRatio, Qt.SmoothTransformation)
item = MonGraphiquePixmapItemOeuvre(pixmap)
item.setTransformationMode(Qt.SmoothTransformation)
item.setFlag(QGraphicsItem.ItemIsFocusable)
self.scene.addItem(item)
self.setScene(self.scene)
###################################################################################
iteme = self.scene.selectedItems()
print("iteme", iteme) # Return []
###################################################################################
self.show()
def supprimer_image_oeuvre(self) :
import sip
tous_items = list(self.scene.items())
print("len(tous_items)", len(tous_items))
print("tous_items", tous_items)
for i in tous_items :
if str(type(i)) != "<class '__main__.MonGraphiquePixmapItemMur'>" :
self.scene.removeItem(tous_items[0])
sip.delete(tous_items[0])
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = TEST()
ex.show()
sys.exit(app.exec_())
Thanks in advance.
I'd have other questions to ask but we'll see that later.
You just have to cycle through selectedItems(), there's absolutely no need to use the sip module, nor check the class using the string (which is not a good way to do so).
def supprimer_image_oeuvre(self) :
for item in self.scene.selectedItems():
self.scene.removeItem(item)
i have a panel with button Dynamic and when i click in button i have a new window opened the problem that i need zone to enter values to edit parameter of dynamic image like that :
that my code :
import wx
class MainFrame(wx.Frame):
def __init__(self,parent):
wx.Frame.__init__(self,parent,title="Myfirst",size=(800,580))
self.top = wx.Panel(self, style = wx.SUNKEN_BORDER)
self.bottom = wx.Panel(self ,style = wx.SUNKEN_BORDER)
self.left = wx.Panel(self ,style = wx.SUNKEN_BORDER, size = (250,-1))
st1 = wx.StaticText(self.bottom, -1, "show info ")
self.bottom.SetBackgroundColour('white')
dynamic=wx.Button(self.left,-1,"Dynamique",size=(110,30),pos=(50,100))
self.Bind(wx.EVT_BUTTON, self.newwindow, dynamic)
sizer1 = wx.BoxSizer(wx.VERTICAL)
sizer1.Add(self.top,1,wx.EXPAND,5)
sizer1.Add(self.bottom,1,wx.EXPAND,5)
sizer2 = wx.BoxSizer(wx.HORIZONTAL)
sizer2.Add(self.left,0,wx.EXPAND,5)
sizer2.Add(sizer1,1,wx.EXPAND,5)
self.SetSizer(sizer2)
def newwindow(self, event):
secondWindow = window2(parent=self.left)
secondWindow.Show()
class window2(wx.Frame):
title = "new Window"
def __init__(self,parent):
wx.Frame.__init__(self,parent, -1,'Dynamic of image', size=(300,100))
panel=wx.Panel(self, -1)
self.SetBackgroundColour(wx.Colour(100,100,100))
self.Centre()
self.Show()
app = wx.App()
frame=MainFrame(None).Show()
app.MainLoop()
how can i add the zone to edit parametre like picture ?
i not sure if the newwindow what i need or dialog !!
thanks for help
I guess you will be fine with a normal new window. You can get the zone to write the parameters with a wx.TextCtrl widgets. You will need a way to export the values typed into the wx.TextCtrl so I added the style wx.TE_PROCESS_ENTER. With this style when you finish typing and press Enter you can process the typed values.
Also, there is no need to use Show() two times (secondWindow.Show() and self.Show()). One of them is enough.
Code with comments:
import wx
class MainFrame(wx.Frame):
def __init__(self,parent):
wx.Frame.__init__(self,parent,title="Myfirst",size=(800,580))
self.top = wx.Panel(self, style = wx.SUNKEN_BORDER)
self.bottom = wx.Panel(self ,style = wx.SUNKEN_BORDER)
self.left = wx.Panel(self ,style = wx.SUNKEN_BORDER, size = (250,-1))
st1 = wx.StaticText(self.bottom, -1, "show info ")
self.bottom.SetBackgroundColour('white')
dynamic=wx.Button(self.left,-1,"Dynamique",size=(110,30),pos=(50,100))
self.Bind(wx.EVT_BUTTON, self.newwindow, dynamic)
sizer1 = wx.BoxSizer(wx.VERTICAL)
sizer1.Add(self.top,1,wx.EXPAND,5)
sizer1.Add(self.bottom,1,wx.EXPAND,5)
sizer2 = wx.BoxSizer(wx.HORIZONTAL)
sizer2.Add(self.left,0,wx.EXPAND,5)
sizer2.Add(sizer1,1,wx.EXPAND,5)
self.SetSizer(sizer2)
def newwindow(self, event):
secondWindow = window2(parent=self.left)
secondWindow.Show()
class window2(wx.Frame):
title = "new Window"
def __init__(self,parent):
"""
This is similar to the class MainFrame. You define a parent wx.Panel
and all other widgets are his childs.
"""
wx.Frame.__init__(self,parent, -1,'Dynamic of image', size=(300,100))
self.panel=wx.Panel(self, -1, style=wx.SUNKEN_BORDER)
self.st = wx.StaticText(self.panel, label='modifier bornes de la dynamique', style=wx.ALIGN_CENTER)
#### Notice the wx.TE_PROCESS_ENTER style to trigger processing the input when
#### Enter is pressed. Another alternative is to put a button somewhere.
self.text = wx.TextCtrl(self.panel, size=(200, 20), style=wx.SUNKEN_BORDER|wx.TE_PROCESS_ENTER)
self.sizer = wx.BoxSizer(wx.VERTICAL)
self.sizer.Add(self.st, 0, wx.EXPAND|wx.ALL, 5)
self.sizer.Add(self.text, 0, wx.ALIGN_CENTER|wx.ALL, 5)
self.panel.SetSizer(self.sizer)
self.sizer.Fit(self.panel)
#self.SetBackgroundColour(wx.Colour(100,100,100))
self.Centre()
#### No need to use Show() here since you already use it in MainFrame.newwindow()
self.Show()
#### To execute self.onEnter when Enter is pressed inside self.text
self.Bind(wx.EVT_TEXT_ENTER, self.onEnter)
def onEnter(self, event):
#### Change it to fit your needs
print(self.text.GetValue())
self.Destroy()
app = wx.App()
frame=MainFrame(None).Show()
app.MainLoop()
i am new to PyQt5 and I try to create a window with grid layout for buttons. But I want to add two labels at top left and bottom right corner of the window.
from PyQt5 import QtWidgets
from PyQt5 import QtCore
import sys
class PrettyWidget(QtWidgets.QWidget):
def __init__(self):
super(PrettyWidget, self).__init__()
self.initUI()
def initUI(self):
self.setGeometry(600,300, 1000, 600)
self.setWindowTitle('Program v1.0')
# Grid Layout
grid = QtWidgets.QGridLayout()
self.setLayout(grid)
self.lbl1 = QtWidgets.QLabel(self)
self.lbl1.setText('Author Information and Copy Right')
self.lbl1.adjustSize()
self.lbl1.move(588, 0)
# Label indicator
self.lbl2 = QtWidgets.QLabel(self)
self.lbl2.setText('Click import to start...')
self.lbl2.adjustSize()
self.lbl2.move(0, 0)
# Import data Button
btn1 = QtWidgets.QPushButton('Select Data', self)
btn1.resize(btn1.sizeHint())
btn1.clicked.connect(self.getData)
grid.addWidget(btn1, 0, 0)
# Import names Button
btn2 = QtWidgets.QPushButton('Select Names', self)
btn2.resize(btn2.sizeHint())
btn2.clicked.connect(self.getNames)
grid.addWidget(btn2, 0, 1)
# Run Button
btn3 = QtWidgets.QPushButton('Run', self)
btn3.resize(btn3.sizeHint())
btn3.clicked.connect(self.Run)
grid.addWidget(btn3, 1, 0)
# Save Button
btn4 = QtWidgets.QPushButton('Save',self)
btn4.resize(btn4.sizeHint())
btn4.clicked.connect(self.Save)
grid.addWidget(btn4, 1, 1)
self.show()
def getData(self):
self.lbl2.setText('Data selected!')
self.lbl2.adjustSize()
def getNames(self):
self.lbl2.setText('Names selected!')
self.lbl2.adjustSize()
def Run(self):
self.lbl2.setText('Done!')
self.lbl2.adjustSize()
def Save(self):
self.lbl2.setText('Saved!')
self.lbl2.adjustSize()
def main():
app = QtWidgets.QApplication(sys.argv)
w = PrettyWidget()
app.exec_()
if __name__ == '__main__':
main()
As you can see I use absolute position for two labels now. So when I maximize or change the window size, the label stays at the same position. How do I stick lbl1 at bottom right and lbl at top left as always?
Paste the labels into the layout.
Set the stretch factor of row row to stretch .
import sys
from PyQt5 import QtWidgets
from PyQt5 import QtCore
class PrettyWidget(QtWidgets.QWidget):
def __init__(self):
super(PrettyWidget, self).__init__()
self.initUI()
def initUI(self):
self.setGeometry(300,100, 1000, 600)
self.setWindowTitle('Program v1.0')
# Grid Layout
grid = QtWidgets.QGridLayout()
self.setLayout(grid)
self.lbl1 = QtWidgets.QLabel(self, alignment=QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter)
self.lbl1.setText('Author Information and Copy Right')
self.lbl1.adjustSize()
grid.addWidget(self.lbl1, 0, 0)
grid.setRowStretch(1, 1) # <---- Sets the stretch factor of row row to stretch .
# Label indicator
self.lbl2 = QtWidgets.QLabel(self, alignment=QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
self.lbl2.setText('Click import to start...')
self.lbl2.adjustSize()
grid.addWidget(self.lbl2, 5, 1)
# Import data Button
btn1 = QtWidgets.QPushButton('Select Data', self)
btn1.resize(btn1.sizeHint())
btn1.clicked.connect(self.getData)
grid.addWidget(btn1, 2, 0)
# Import names Button
btn2 = QtWidgets.QPushButton('Select Names', self)
btn2.resize(btn2.sizeHint())
btn2.clicked.connect(self.getNames)
grid.addWidget(btn2, 2, 1)
# Run Button
btn3 = QtWidgets.QPushButton('Run', self)
btn3.resize(btn3.sizeHint())
btn3.clicked.connect(self.Run)
grid.addWidget(btn3, 3, 0)
# Save Button
btn4 = QtWidgets.QPushButton('Save',self)
btn4.resize(btn4.sizeHint())
btn4.clicked.connect(self.Save)
grid.addWidget(btn4, 3, 1)
grid.setRowStretch(4, 1) # <---- Sets the stretch factor of row row to stretch .
self.show()
def getData(self):
self.lbl2.setText('Data selected!')
self.lbl2.adjustSize()
def getNames(self):
self.lbl2.setText('Names selected!')
self.lbl2.adjustSize()
def Run(self):
self.lbl2.setText('Done!')
self.lbl2.adjustSize()
def Save(self):
self.lbl2.setText('Saved!')
self.lbl2.adjustSize()
def main():
app = QtWidgets.QApplication(sys.argv)
w = PrettyWidget()
app.exec_()
if __name__ == '__main__':
main()
I'm creating a simple PySide application that also uses MatPlotLib. However, when I add the figure into a QFrame, the figure doesn't automatically fit to the frame:
My graph is created using the following code:
class GraphView(gui.QWidget):
def __init__(self, name, title, graphTitle, parent = None):
super(GraphView, self).__init__(parent)
self.name = name
self.graphTitle = graphTitle
self.dpi = 100
self.fig = Figure((5.0, 3.0), dpi = self.dpi, facecolor = (1,1,1), edgecolor = (0,0,0))
self.axes = self.fig.add_subplot(111)
self.canvas = FigureCanvas(self.fig)
self.Title = gui.QLabel(self)
self.Title.setText(title)
self.layout = gui.QVBoxLayout()
self.layout.addStretch(1)
self.layout.addWidget(self.Title)
self.layout.addWidget(self.canvas)
self.setLayout(self.layout)
def UpdateGraph(self, data, title = None):
self.axes.clear()
self.axes.plot(data)
if title != None:
self.axes.set_title(title)
self.canvas.draw()
And it's added to the main Widget like so:
# Create individual Widget/Frame (fftFrame)
fftFrame = gui.QFrame(self)
fftFrame.setFrameShape(gui.QFrame.StyledPanel)
self.FFTGraph = GraphView('fftFrame', 'FFT Transform:', 'FFT Transform of Signal', fftFrame)
Here's a working code sample that shows you how to get it working. I first thought it was because of the stretch you added to the layout, which will use up the additional space around the other widgets. But when I removed it, it still wouldn't resize. The 'easy' solution is to add a resizeEvent, which lets you define the size of your GraphView widget. In this case I just set its geometry to be that of the QFrame, though you might want to add some padding and make sure you set a sensible minimum size for the QFrame.
from PySide import QtGui
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.figure import Figure
import sys
class MainWindow(QtGui.QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.fft_frame = FftFrame(self)
self.layout = QtGui.QVBoxLayout()
self.layout.addWidget(self.fft_frame)
self.setLayout(self.layout)
self.setCentralWidget(self.fft_frame)
class FftFrame(QtGui.QFrame):
def __init__(self, parent=None):
super(FftFrame, self).__init__(parent)
self.setFrameShape(QtGui.QFrame.StyledPanel)
self.parent = parent
self.graph_view = GraphView('fftFrame', 'FFT Transform:', 'FFT Transform of Signal', self)
def resizeEvent(self, event):
self.graph_view.setGeometry(self.rect())
class GraphView(QtGui.QWidget):
def __init__(self, name, title, graph_title, parent = None):
super(GraphView, self).__init__(parent)
self.name = name
self.graph_title = graph_title
self.dpi = 100
self.fig = Figure((5.0, 3.0), dpi = self.dpi, facecolor = (1,1,1), edgecolor = (0,0,0))
self.axes = self.fig.add_subplot(111)
self.canvas = FigureCanvas(self.fig)
self.canvas.setParent(self)
self.Title = QtGui.QLabel(self)
self.Title.setText(title)
self.layout = QtGui.QVBoxLayout()
self.layout.addWidget(self.Title)
self.layout.addWidget(self.canvas)
self.layout.setStretchFactor(self.canvas, 1)
self.setLayout(self.layout)
self.canvas.show()
def update_graph(self, data, title = None):
self.axes.clear()
self.axes.plot(data)
if title != None:
self.axes.set_title(title)
self.canvas.draw()
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec_()