PySide6 QListWidget dragging a row to its index deletes the row - qlistwidget

import sys, os
from PySide6.QtCore import *
from PySide6.QtGui import *
from PySide6.QtWidgets import *
from ui_listitem import *
class myItem(QWidget):
def __init__(self, parent = None) -> None:
super().__init__(parent=parent)
self.ui = Ui_rootWidget() # this ui just have 2 text labels horizontal aligned
self.ui.setupUi(self)
class myList(QListWidget):
def __init__(self, parent = None) -> None:
super().__init__(parent=parent)
self.resize(400, 400)
self.setDragDropMode(QAbstractItemView.DragDropMode.InternalMove)
for i in range(10):
wi = QListWidgetItem(self)
wi.widget = myItem(self)
wi.widget.ui.label1.setText(f'text{i}')
wi.widget.ui.label2.setText(f'text{i}')
wi.setSizeHint(wi.widget.sizeHint())
self.addItem(wi)
self.setItemWidget(wi, wi.widget)
if __name__ == '__main__':
app = QApplication(sys.argv)
w = myList()
w.show()
sys.exit(app.exec())
result:
uh..I don't know what it happened. What should I do to get it to work?
I read a post(InternalMove in QListWidget makes item disappear). I tried setDefaultDropAction(Qt.TargetMoveAction) or setMovement(QListView.Free) or both but not worked.
I am using python 3.9.7, pyside 6.2.1, on Windows 10 Pro 20H2 19042.1348 build.
Addition.
A similar but not identical disappearance occurs in a QListView without a custom widget.
import sys, os
from PySide6.QtCore import *
from PySide6.QtGui import *
from PySide6.QtWidgets import *
class myDelegate(QStyledItemDelegate):
def sizeHint(self, option, index):
return QSize(350, 35)
class myList(QListView):
def __init__(self, parent = None) -> None:
super().__init__(parent=parent)
self.resize(400, 400)
self.setDragDropMode(QAbstractItemView.DragDropMode.InternalMove)
self.model = QStandardItemModel(self)
self.setModel(self.model)
self.delegate = myDelegate(self)
self.setItemDelegate(self.delegate)
for i in range(10):
item = QStandardItem(f'text{i}')
self.model.appendRow(item)
self.setDragDropOverwriteMode(False)
if __name__ == '__main__':
app = QApplication(sys.argv)
w = myList()
w.show()
sys.exit(app.exec())
result:
I tried setDefaultDropAction with Qt.MoveAction, Qt.CopyAction or Qt.TargetMoveAction but all not worked.
Are these all originally intended? Please let me know how to move items in listview or listwidget without disappearing. Or maybe it's impossible?

Related

tkinter GUI freezes while plotting voltages of an Arduino

I am just trying to write a GUI to help me while measuring. For now, I want to be able to plot -Voltages for example- in real-time from my Arduino UNO. Sadly this code just works fine for around 5 seconds, after this the tkinter windows freezes. Amazingly the v and t list works. Would you please give me a hint to fix this problem? I just spend hours.
from pyfirmata import Arduino, util
import matplotlib
matplotlib.use('TkAgg')
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.figure import Figure
from tkinter import *
import time
import threading
board=Arduino('COM3')
iterator = util.Iterator(board)
iterator.start()
Tvl = board.get_pin('a:0:i')
class mclass(threading.Thread):
def __init__(self, window):
threading.Thread.__init__(self)
self.window = window
self.box = Entry(window)
self.button = Button (window, text="check", command=self.plot)
self.box.pack ()
self.button.pack()
self.t=[]
self.v=[]
self.fig = Figure(figsize=(6,6))
self.a = self.fig.add_subplot(111)
self.a.invert_yaxis()
self.a.set_title ("Estimation Grid", fontsize=16)
self.a.set_ylabel("Y", fontsize=14)
self.a.set_xlabel("X", fontsize=14)
self.canvas = FigureCanvasTkAgg(self.fig, master=self.window)
self.canvas.get_tk_widget().pack(side=BOTTOM, fill=BOTH, expand=False)
def plot (self):
global t,v
clock=time.perf_counter()
while time.perf_counter()-clock<=float(self.box.get()):
self.v.append(Tvl.read())
self.t.append(time.perf_counter()-clock)
if len(self.v)>=25:
del self.v[0]
del self.t[0]
self.a.clear()
self.a.plot(self.t,self.v)
self.canvas.draw()
window= Tk()
t= mclass(window)
t.start()
window.mainloop()
I thank you for your comments. In the end patthoyts hint worked quite well. I would be verry interested why while loops in this case dont work.
Beneath ist the new stable Code with some more Features added.
thanks and greets peterudo
from pyfirmata import Arduino, util
import matplotlib
matplotlib.use('TkAgg')
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.figure import Figure
from tkinter import *
import time
import threading
board=Arduino('COM3')
iterator = util.Iterator(board)
iterator.start()
Tvl = board.get_pin('a:0:i')
class mclass(threading.Thread):
def __init__(self, window):
threading.Thread.__init__(self)
self.window = window
self.box = Entry(window)
self.box.pack ()
self.button = Button (window, text="check", command=self.plot)
self.button.pack()
self.button2 = Button(window,text="stop", command=self.start_stop)
self.button2.pack()
self.w=Scale(window, from_=0, to=10000)
self.w.pack()
self.w2=Scale(window, from_=0, to=100000)
self.w2.pack()
self.t=[]
self.v=[]
self.ss=True
self.fig = Figure(figsize=(6,6))
self.a = self.fig.add_subplot(111)
self.a.invert_yaxis()
self.a.set_title ("Estimation Grid", fontsize=16)
self.a.set_ylabel("Y", fontsize=14)
self.a.set_xlabel("X", fontsize=14)
self.canvas = FigureCanvasTkAgg(self.fig, master=self.window)
self.canvas.get_tk_widget().pack(side=BOTTOM, fill=BOTH, expand=False)
def plot (self):
window.after(10, self.plot)
if self.ss==True:
self.v.append(Tvl.read())
self.t.append(time.perf_counter())
if self.t[0]<self.t[len(self.t)-1]-0.0001*self.w2.get():
del self.v[0]
del self.t[0]
self.a.clear()
self.a.set_ylim(Tvl.read()-0.0001*self.w.get(),Tvl.read()+0.0001*self.w.get())
self.a.set_xlim(self.t[len(self.t)-1]-0.001*self.w2.get()+1,time.perf_counter())
self.a.plot(self.t,self.v)
self.canvas.draw()
def start_stop(self):
if self.ss==True:
self.ss=False
else:
self.ss=True
window= Tk()
t= mclass(window)
t.start()
window.mainloop()

python - checkbox in new window update fails and stays false

import matplotlib
from tkinter import *
matplotlib.use("TkAgg")
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2TkAgg
import tkinter as tk
from tkinter import ttk
import numpy as np
import matplotlib.animation as animation
from matplotlib import style
from matplotlib import pyplot as plt
from scipy.misc import *
import webbrowser
import subprocess
import csv
import matplotlib.ticker as mticker
import matplotlib.dates as mdates
from os import startfile
LARGE_FONT = ("Times", 11, "bold italic")
NORM_FONT = ("Helvetica", 9)
SMALL_FONT = ("Helvetica",7)
HELP_FONT=("Times", 9 , "bold")
class PAL3_guide(tk.Tk):
def __init__(self,*args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
container = tk.Frame(self)
container.pack(side="top", fill="both", expand = True)
container.grid_rowconfigure(0, weight=1)
container.grid_columnconfigure(0, weight=1)
self.frames = {}
for F in (StartPage,Tut01):
frame = F(container, self)
self.frames[F] = frame
frame.grid(row=0, column=0, sticky="nsew")
self.show_frame(StartPage)
def show_frame(self, cont):
frame=self.frames[cont]
frame.tkraise()
class StartPage(tk.Frame):
def __init__(self,parent, controller):
tk.Frame.__init__(self,parent, background="white")
button_PAL = ttk.Button(self, text="Setup Guide", command=lambda:controller.show_frame(Tut01))
button_PAL.pack()
class Tut01(tk.Frame):
def __init__(self,parent,controller):
tk.Frame.__init__(self,parent)
var=BooleanVar()
label = tk.Label(self, text="Guide", font=LARGE_FONT)
label.pack(pady=10, padx=10)
label = tk.Label(self, text="Check the methods to accomplish", font=NORM_FONT)
label.pack(pady=10, padx=10)
c1 = Checkbutton(self, state=ACTIVE).pack()
c1Label = tk.Label(self, text="digestion1",font=SMALL_FONT).pack()
c2 = Checkbutton(self, state=ACTIVE).pack()
c2Label = tk.Label(self, text="digestion2",font=SMALL_FONT).pack()
c3 = Checkbutton(self, text="enrichment",state=ACTIVE, variable=var, command=lambda:onClick()).pack()
def onClick():
var.get()
if var == True:
print("hi")
else:
print("hiww")
app = PAL3_guide()
app.geometry("1280x920")
app.mainloop()
Please check last code lines around the c3 checkbox.
I dont get why my boolean variable var is not getting updated by clicking the checkbox on the 2nd page. By clicking the checkbox (c3) the GUI should act differently. However as mentioned above it is not getting updated.. and stays False. I feel it keeps the value from start and does not get changed. Thanks for help ..
EDIT:
Above the if statement missed the var.get() and I could make it work in smaller setup.. however, in the real tool I am calling a plt.figure() in the beginning since it included and anmiate function, If I erase this call, everything works like it should, might be that this figure calling forces the checkbutton to have the first onvalue ?
I would change var, to be self.var and set the off and on values explicitly:
offvalue=
The value corresponding to a non-checked button. The default is 0. (offValue/Value)
onvalue=
The value corresponding to a checked button. The default is 1. (onValue/Value)
c3 = Checkbutton(self, text="enrichment",state=ACTIVE,
variable=self.var, command=onClick,
onvalue=True, offvalue=False)
c3.pack()
command= does not take a function call, just a function.
You would have to write either
command=lambda: print(self.var.get())
OR:
def printVar():
print(self.var.get())
THEN:
..., command=printVar, ...
NOTICE the abscence of the paranthesis!
You are supposed to be settting command to a function.
When you use parenthesis, you CALL the function, you DO NOT want that here.

Unable to implement mpl_connect

I'm working on a GUI that basically hold multiple widgets that each contain a figure as well as a few buttons/whatever. One of the figures is supposed to be interactive, calling a function whenever the user clicks on any part of the plot. Yet I can't get the function to fire using mpl_connect, even after playing with focus and whatnot. I'm somewhat new to PySide/Qt, so I don't exactly understand why my code is behaving like this (I've been searching for days for a solution, but haven't found anything about it).
I used Qt Designer to create the layout for the GUI. I'm using Spyder from Anaconda 2.2.0 (32-bit), Python 2.7, and PySide to develop the GUI. If it's any help, I come from more of a MATLAB background where I developed a full version of the GUI I'm trying to make in Python.
Below is the relevant code (scroll down a bit to see where the problem is):
from PySide import QtCore, QtGui
from PySide.QtCore import *
from PySide.QtGui import *
import numpy as np
import matplotlib
matplotlib.use('Qt4Agg')
matplotlib.rcParams['backend.qt4']='PySide'
from matplotlib.figure import Figure
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.backends.backend_qt4agg import NavigationToolbar2QTAgg as NavigationToolbar
import matplotlib.pyplot as plt
from PySide.QtGui import QPalette, QCursor
import matplotlib.colors as colors
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(1316, 765)
self.centralwidget = QtGui.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.widget = QtGui.QWidget(self.centralwidget)
self.widget.setGeometry(QtCore.QRect(75, 40, 375, 490))
self.widget.setObjectName("widget")
color = self.centralwidget.palette().color(QPalette.Window)
self.leftPlot = MatplotlibWidget(None,'','','',False,color)
self.setupPlot(self.widget,self.leftPlot)
self.leftPlot.figure.tight_layout()
self.leftImage = self.leftPlot.axes.imshow(self.defaultSlide, cmap = mymap)
Snippet of interest:
self.leftPlot.figure.canvas.setFocusPolicy(QtCore.Qt.StrongFocus)
self.leftPlot.figure.canvas.setFocus()
cid = self.leftPlot.figure.canvas.mpl_connect('button_release_event', self.getCoordinates) # doesn't get called
plt.show()
def getCoordinates(self, event):
print 'dasdsadadsa'
print 'button=%d, x=%d, y=%d, xdata=%f, ydata=%f'%(event.button, event.x, event.y, event.xdata, event.ydata)
The rest:
class MatplotlibWidget(FigureCanvas):
def __init__(self, parent=None,xlabel='x',ylabel='y',title='Title',showTicks=False,color=None):
super(MatplotlibWidget, self).__init__(Figure())
self.setParent(parent)
if color != None:
self.figure = Figure(facecolor=(color.red()/256.0,color.green()/256.0,color.blue()/256.0),frameon=0)
else:
self.figure = Figure(frameon=0)
self.canvas = FigureCanvas(self.figure)
self.axes = self.figure.add_subplot(111)
self.axes.set_xlabel(xlabel)
self.axes.set_ylabel(ylabel)
self.axes.set_title(title)
self.axes.get_xaxis().set_visible(showTicks)
self.axes.get_yaxis().set_visible(showTicks)
class ControlMainWindow(QtGui.QMainWindow):
def __init__(self, parent=None):
super(ControlMainWindow, self).__init__(parent)
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
plt.show()
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
mySW = ControlMainWindow()
mySW.show()
sys.exit(app.exec_())
I'm aware the code is messy, but any input is greatly appreciated.
Update (2015-09-04) : I've updated the MWE I provided as part of my original answer to use instead the approach that is suggested in the matplotlib documentation to embed a mpl figure in an application. This approach does not use the pyplot interface (as in my original answer) and use the Object Oriented API of mpl instead. Also, since all the mpl artists (figure, axes, etc.) know each other, there is no need to explicitly create new class variables. This allows a structure of code that is, IMO, easier to read and to maintain.
The problem comes from the fact that you are not connecting correctly your event to self.leftPlot (FigureCanvasQTAgg), but to self.leftPlot.figure.canvas (FigureCanvasQTAgg.figure.FigureCanvasQTAgg) instead. You are creating a canvas within a canvas in the MatplotlibWidget class (which is already a subclass of FigureCanvasQTAgg). You only need to create one mpl canvas, pass a figure to it, and then connect the event to it directly.
I've put together a MWE to demonstrate how this can be done using the Object Oriented API of Matplotlib as suggested in the documentation:
from PySide import QtGui
import numpy as np
import sys
import matplotlib as mpl
mpl.use('Qt4Agg')
mpl.rcParams['backend.qt4']='PySide'
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg
class ControlMainWindow(QtGui.QMainWindow):
def __init__(self, parent=None):
super(ControlMainWindow, self).__init__(parent)
self.setupUi()
def setupUi(self):
figure = mpl.figure.Figure(figsize=(5, 5))
leftPlot = MatplotlibWidget(figure)
self.setCentralWidget(leftPlot)
class MatplotlibWidget(FigureCanvasQTAgg):
def __init__(self, fig):
super(MatplotlibWidget, self).__init__(fig)
#-- set up an axe artist --
ax = fig.add_axes([0.1, 0.1, 0.85, 0.85])
ax.plot(np.arange(15), np.arange(15))
self.draw()
#---- setup event ----
self.mpl_connect('button_press_event', self.onclick)
def onclick(self, event):
x, y = event.x, event.y
print(x, y)
if x != None and y != None:
ax = self.figure.axes[0]
ax.plot(event.xdata, event.ydata, 'ro')
self.draw()
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
mySW = ControlMainWindow()
mySW.show()
sys.exit(app.exec_())
The code above results in:

Embedding Matplotlib in Tkinter doesn't dispay anything

I am trying to use the figure that is being created inside the class "SubplotAnimation" and place it to my graph page but it doesn't work.. Please help me... Here is my code (Tried to take all the unnecessary stuff, but some are left...):
import matplotlib
matplotlib.use("TkAgg")
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2TkAgg
#import tkinter as tk
import Tkinter as tk
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.lines import Line2D
import matplotlib.animation as animation
class SubplotAnimation(animation.TimedAnimation):
def __init__(self):
fig = plt.figure()
fig.set_size_inches(10, 7)
ax2 = plt.subplot2grid((2, 2), (0, 0), colspan=2)
ax3 = plt.subplot2grid((2, 2), (1, 0), colspan=2)
self.t = np.linspace(0, 80, 400)
self.x = np.cos(2 * np.pi * self.t / 10.)
self.y = np.sin(2 * np.pi * self.t / 10.)
self.z = 10 * self.t
ax2.set_xlabel('y')
ax2.set_ylabel('z')
self.line2 = Line2D([], [], color='black')
ax2.add_line(self.line2)
ax2.set_xlim(0, 800)
ax2.set_ylim(-1, 1)
ax3.set_xlabel('x')
ax3.set_ylabel('z')
self.line3 = Line2D([], [], color='black')
ax3.add_line(self.line3)
ax3.set_xlim(0, 800)
ax3.set_ylim(-1, 1)
animation.TimedAnimation.__init__(self, fig, interval=50, blit=True)
def _draw_frame(self, framedata):
i = framedata
self.line2.set_data(self.z[:i], self.y[:i])
self.line3.set_data(self.z[:i], self.x[:i])
self._drawn_artists = [self.line2, self.line3]
def new_frame_seq(self):
return iter(range(self.t.size))
def _init_draw(self):
lines = [self.line2, self.line3]
for l in lines:
l.set_data([], [])
#ani.save('test_sub.mp4')
#property
def fig(self):
return self._fig
plt.show()
class MainPage(tk.Tk):
def __init__(self, *args, **kwargs):
root = tk.Tk.__init__(self, *args, **kwargs)
tk.Tk.wm_title(self, "Heeeeelp")
container = tk.Frame(self)
container.pack(side="top", fill="both", expand=True)
container.grid_rowconfigure(0, weight=1)
container.grid_columnconfigure(0, weight=1)
#********** FRAMES*******#
self.frames = {} #empty..
frame = GraphPage(container, self)
self.frames[GraphPage] = frame
frame.grid(row=0, column=0, sticky="nsew")
self.show_frame(GraphPage)
def show_frame(self, cont):
frame = self.frames[cont]
frame.tkraise()
class GraphPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self,parent)
label = tk.Label(self, text="Help")
label.grid(row=0, column=0, sticky='NW')
ani = SubplotAnimation()
canvas = FigureCanvasTkAgg(ani.fig, self)
canvas.show()
canvas.get_tk_widget().grid(row=1, column=0, rowspan=6, columnspan=3, sticky='NSEW')
app = MainPage()
app.geometry("980x640")
app.mainloop()
Okay, some things are needed to make this work.
First of all, I don't really understand why you have the code
#property
def fig(self):
return self._fig
but I think you need to just delete this. Also remove the plt.show() beneath it since that does nothing.
Then you need to rename fig in SubplotAnimation to self.fig:
self.fig = plt.figure()
self.fig.set_size_inches(10, 7)
Lastly, you should take the call to animation.TimedAnimation.__init__, put it right behind canvas = FigureCanvasTkAgg(ani.fig, self) and change it to
animation.TimedAnimation.__init__(ani, ani.fig, interval=50, blit=True)
I believe that are all the steps needed to make it work.
If you want to keep the initialization of the animation in your SubplotAnimation class, you can also make a new function to initialize it like
def _init_animation(self):
animation.TimedAnimation.__init__(self, self.fig, interval=50, blit=True)
And call it after canvas = FigureCanvasTkAgg(...) using
ani._init_animation()

pyQT4: How to open a window from another window

I'm trying to open a window (QWidget) when clicking on a button. My problem is that the second window doesn't show up when I click on the button no matter what I've tried. The two windows are created using QTDesigner.
Here is a little snippet explaining what I'm trying to do:
from PyQt4.QtGui import *
from PyQt4.QtCore import *
from win1 import *
from win2 import *
import sys
class win1(QWidget, Ui_Win1):
def __init__(self, parent = None):
self.parent = parent
QWidget.__init__(self)
self.setupUi(parent)
self.connect(self.pushButton, SIGNAL("clicked()"), self.on_btn_clicked)
def on_btn_clicked(self):
self.child = win2(self.parent)
self.child.show()
class win2(QWidget, Ui_Win2):
def __init__(self, parent = None):
QWidget.__init__(self)
self.setupUi(parent)
def main(args):
app = QApplication(args)
win = QWidget()
a = win1(win)
win.show()
result = app.exec_()
if __name__=="__main__":
main(sys.argv)
What am I missing here ?
Thanks.
Not sure, but two random thoughts:
If you add a print statement to on_btn_clicked, do you see anything when you click on the button? This would diagnose whether it's an event triggering issue
Does it work if you change the setupUI(parent) commands to setupUI(self)?

Resources