I have a program that has you drag and drop files into a QListWidget box and then you click a button to upload those files to a bucket. I would like to say which files have been uploaded and which one is currently being uploaded with an icon. Is there a way to add Icons inside/next to the QListWidget box?
Here is some of the code for the QListWidget and the drag and drop feature. I am just hoping there is a way to add icons
import sys, os
from PyQt5.QtWidgets import QApplication, QMainWindow, QListWidget, QListWidgetItem, QPushButton
from PyQt5.QtCore import Qt, QUrl
class ListBoxWidget(QListWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.setAcceptDrops(True)
self.resize(600, 600)
def dragEnterEvent(self, event):
if event.mimeData().hasUrls:
event.accept()
else:
event.ignore()
def dragMoveEvent(self, event):
if event.mimeData().hasUrls():
event.setDropAction(Qt.CopyAction)
event.accept()
else:
event.ignore()
def dropEvent(self, event):
if event.mimeData().hasUrls():
event.setDropAction(Qt.CopyAction)
event.accept()
links = []
for url in event.mimeData().urls():
# https://doc.qt.io/qt-5/qurl.html
if url.isLocalFile():
links.append(str(url.toLocalFile()))
else:
links.append(str(url.toString()))
self.addItems(links)
else:
event.ignore()
class AppDemo(QMainWindow):
def __init__(self):
super().__init__()
self.resize(1200, 600)
self.listbox_view = ListBoxWidget(self)
self.btn = QPushButton('Get Value', self)
self.btn.setGeometry(850, 400, 200, 50)
self.btn.clicked.connect(lambda: print(self.getSelectedItem()))
def getSelectedItem(self):
item = QListWidgetItem(self.listbox_view.currentItem())
return item.text()
if __name__ == '__main__':
app = QApplication(sys.argv)
demo = AppDemo()
demo.show()
sys.exit(app.exec_())
I have tried adding QIcon to the self.addItems(links) line but it continues to give me an error about arguments.
Instead of adding items using addItems, create indivual QListWidgetItems and add them one by one using addItem(QListWidgetItem).
def dropEvent(self, event):
if event.mimeData().hasUrls():
event.setDropAction(Qt.CopyAction)
event.accept()
for url in event.mimeData().urls():
# https://doc.qt.io/qt-5/qurl.html
if url.isLocalFile():
address = str(url.toLocalFile())
icon = QIcon('localIcon.png')
else:
address = str(url.toString())
icon = QIcon('remoteIcon.png')
self.addItem(QListWidgetItem(icon, address))
If you want to change the icon of an existing item, access it using item() and use setIcon():
def setIconForItem(self, row, icon):
self.listbox_view.item(row).setIcon(icon)
Related
I want to know how to keep scene widgets after add them to scene for later.
After user's click on marker button, marker feature active and with rightclick can mark points in QGraphicscene.
Here is my code:
from PyQt5.QtWidgets import QMainWindow, QToolButton, QGraphicsScene, QGraphicsPixmapItem
from PyQt5.QtGui import QPixmap, QIcon, QPainter
from PyQt5 import uic
from PyQt5.QtCore import Qt
class MarkerButton(QToolButton):
def __init__(self, *args, **kwargs):
super(MarkerButton, self).__init__(*args, **kwargs)
def mousePressEvent(self, event):
if event.buttons() & Qt.LeftButton:
self.deleteLater()
super().mousePressEvent(event)
class MarkerScene(QGraphicsScene):
def __init__(self, *args, **kwargs):
super(MarkerScene, self).__init__(*args, **kwargs)
self.marker_widgets = dict()
def mousePressEvent(self, event):
if event.buttons() & Qt.RightButton:
self.start_point = event.scenePos()
self.update_path()
super().mousePressEvent(event)
def update_path(self):
if not self.start_point.isNull():
pushButton_icon = QIcon()
pushButton_icon.addPixmap(QPixmap('assets/mark.png'))
new_marker = MarkerButton()
new_marker.setToolButtonStyle(Qt.ToolButtonTextUnderIcon)
new_marker.move(int(self.start_point.x()), int(self.start_point.y()))
new_marker.setIcon(pushButton_icon)
new_marker.setText(str(len(self.marker_widgets)))
self.addWidget(new_marker)
self.marker_widgets[new_marker] = self.start_point
class Ui(QMainWindow):
def __init__(self):
super(Ui, self).__init__() # Call the inherited classes __init__ method
self.Window_obj= uic.loadUi('main.ui')
self.Window_obj.setWindowFlags(Qt.FramelessWindowHint)
pix = QPixmap('assets/data.png')
item = QGraphicsPixmapItem(pix)
scene = QGraphicsScene(self)
scene.addItem(item)
self.Window_obj.graphicsViewScene1.setScene(scene)
self.Window_obj.show()
def AddMarker(self):
if not self.active_toolbox_markers:
self.active_toolbox_markers = True
self.main_Window_obj.graphicsViewScene1.setRenderHint(QPainter.Antialiasing)
self.Window_obj.graphicsViewScene1.setMouseTracking(True)
scene = MarkerScene()
self.main_Window_obj.graphicsViewScene1.setScene(scene)
else:
self.active_toolbox_markers = False
I need to save this markers for later but user have to be able to hide them, the reason is because I have another tool that I want not conflict with this markers.
At the end, after add markers, the main Qpixmap removed.
my app something like this
I have a scene like this
class Scene(QtWidgets.QGraphicsScene):
def __init__(self, parent=None):
super(Scene, self).__init__(parent)
def mousePressEvent(self, event):
print('scene pressed')
self.wid = MyRect(event.pos(), event.pos())
self.addItem(self.wid)
self.wid.show()
I would like class MyRect(QtWidgets.QGraphicsRectItem) with painter, mouse event and so on to be a draggable rectangle.
all stuff in MyRect
So then I could have many Rectangle to the scene and even after draw line between them and so on (kind of diagram app), but keeping objects related editable options in MyRect, MyLine , ....
I thought :
class MyRect(QtWidgets.QGraphicsRectItem):
def __init__(self, begin, end, parent=None):
super().__init__(parent)
self.begin = begin
self.end = end
def paintEvent(self, event):
print('painting')
qp = QtGui.QPainter(self)
qp.drawRect(QtCore.QRect(self.begin, self.end))
def mousePressEvent(self, event):
self.begin = event.pos()
self.end = event.pos()
self.update()
def mouseMoveEvent(self, event):
self.end = event.pos()
self.update()
def mouseReleaseEvent(self, event):
self.begin = event.pos()
self.end = event.pos()
self.update()
But I does not work (paint event not initiated whereas mousepressed event in scene is intiated)
I did not find what I wanted through the web so started totry do it by myself. I'm pretty sure it is a must known starting point but I cannot find it
First of all a QGraphicsItem is not a QWidget, so it has those events and does not handle them directly, that's what QGraphicsView and QGraphicsScene do. For example you say that you want to have a moveable rectangle because that task is simple is QGraphicsView, it is not necessary to overwrite:
from PyQt5 import QtCore, QtWidgets
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
scene = QtWidgets.QGraphicsScene(self)
view = QtWidgets.QGraphicsView(scene)
self.setCentralWidget(view)
rect_item = QtWidgets.QGraphicsRectItem(QtCore.QRectF(0, 0, 100, 100))
rect_item.setFlag(QtWidgets.QGraphicsItem.ItemIsMovable, True)
scene.addItem(rect_item)
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
w = MainWindow()
w.resize(640, 480)
w.show()
sys.exit(app.exec_())
If you want to change the way you paint the rectangle you must overwrite the paint() method as shown below:
from PyQt5 import QtCore, QtGui, QtWidgets
class RectItem(QtWidgets.QGraphicsRectItem):
def paint(self, painter, option, widget=None):
super(RectItem, self).paint(painter, option, widget)
painter.save()
painter.setRenderHint(QtGui.QPainter.Antialiasing)
painter.setBrush(QtCore.Qt.red)
painter.drawEllipse(option.rect)
painter.restore()
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
scene = QtWidgets.QGraphicsScene(self)
view = QtWidgets.QGraphicsView(scene)
self.setCentralWidget(view)
rect_item = RectItem(QtCore.QRectF(0, 0, 100, 100))
rect_item.setFlag(QtWidgets.QGraphicsItem.ItemIsMovable, True)
scene.addItem(rect_item)
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
w = MainWindow()
w.resize(640, 480)
w.show()
sys.exit(app.exec_())
Update:
from PyQt5 import QtCore, QtGui, QtWidgets
class GraphicsScene(QtWidgets.QGraphicsScene):
def __init__(self, parent=None):
super(GraphicsScene, self).__init__(QtCore.QRectF(-500, -500, 1000, 1000), parent)
self._start = QtCore.QPointF()
self._current_rect_item = None
def mousePressEvent(self, event):
if self.itemAt(event.scenePos(), QtGui.QTransform()) is None:
self._current_rect_item = QtWidgets.QGraphicsRectItem()
self._current_rect_item.setBrush(QtCore.Qt.red)
self._current_rect_item.setFlag(QtWidgets.QGraphicsItem.ItemIsMovable, True)
self.addItem(self._current_rect_item)
self._start = event.scenePos()
r = QtCore.QRectF(self._start, self._start)
self._current_rect_item.setRect(r)
super(GraphicsScene, self).mousePressEvent(event)
def mouseMoveEvent(self, event):
if self._current_rect_item is not None:
r = QtCore.QRectF(self._start, event.scenePos()).normalized()
self._current_rect_item.setRect(r)
super(GraphicsScene, self).mouseMoveEvent(event)
def mouseReleaseEvent(self, event):
self._current_rect_item = None
super(GraphicsScene, self).mouseReleaseEvent(event)
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
scene =GraphicsScene(self)
view = QtWidgets.QGraphicsView(scene)
self.setCentralWidget(view)
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
w = MainWindow()
w.resize(640, 480)
w.show()
sys.exit(app.exec_())
I would like a little help, I am trying to generate a chat room but I would like that the QLabel that I use to show the messages had the form of a message container like this
And not only with the typical square shape of a QLabel
I tried to do the following:
def CreateLabel(self):
image = QtGui.QPixmap("container.png")
mask = image.createMaskFromColor(QtCore.Qt.red)
self.Label = QLabel()
self.Label.setText("Test Text")
self.Label.setAlignment(QtCore.Qt.AlignRight)
self.Label.setMask(mask)
Try it:
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
class Label(QLabel):
def __init__(self, text):
super().__init__()
self.text = text
self.im = QImage('D:/_Qt/img/chat.png')
self.resize(self.im.size())
def paintEvent(self, event):
super().paintEvent(event)
p = QPainter(self)
p.drawImage(0, 0, self.im)
self.drawText(event, p)
def drawText(self, event, p):
p.setPen(QColor(168, 34, 4))
p.setFont(QFont('Decorative', 12))
p.drawText(event.rect(), Qt.AlignTop, self.text)
def closeEvent(self, event):
quit()
class Widget(QWidget):
def __init__(self):
super().__init__()
self.text = """
How to draw a QLabel with chat image.
I would like a little help, I am trying to generate a chat
room but I would like that the QLabel that I use to show
the messages had the form of a message container like this.
"""
self.label = Label(self.text)
self.label.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
w = Widget()
# w.show()
app.exec_()
I am writing a program with pyqt5 where pressing a button first cycles through some pictures then cycles through some videos.
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtMultimedia import *
from PyQt5.QtMultimediaWidgets import *
import glob
import argparse
import sys
class MainWindow(QMainWindow):
def __init__(self,args):
super(MainWindow, self).__init__()
self.setWindowTitle('Navon test')
self.setWindowFlags(Qt.FramelessWindowHint)
# exit option for the menu bar File menu
self.exit = QAction('Exit', self)
self.exit.setShortcut('Ctrl+q')
# message for the status bar if mouse is over Exit
self.exit.setStatusTip('Exit program')
# newer connect style (PySide/PyQT 4.5 and higher)
self.exit.triggered.connect(app.quit)
self.setWindowIcon(QIcon('icon.ico'))
self.centralwidget = CentralWidget(args)
self.setCentralWidget(self.centralwidget)
def keyPressEvent(self, QKeyEvent):
if QKeyEvent.key() == Qt.Key_Escape:
QCoreApplication.instance().quit()
self.centralwidget.startvid()
class CentralWidget(QWidget):
def __init__(self,args):
super(CentralWidget, self).__init__()
self.layout = QVBoxLayout()
self.layout.setAlignment(Qt.AlignCenter)
self.setLayout(self.layout)
self.player = QMediaPlayer(None, QMediaPlayer.VideoSurface)
self.vw = QVideoWidget()
self.player.setVideoOutput(self.vw)
def startvid(self):
self.layout.addWidget(self.vw)
url= QUrl.fromLocalFile(glob.glob("videos/*")[0])
content= QMediaContent(url)
self.player.setMedia(content)
self.player.setVideoOutput(self.vw)
self.player.play()
if __name__== "__main__":
parser = argparse.ArgumentParser()
#~ parser.add_argument("-nb","--nobox",action="store_true", help="do not wait for the box connection")
args = parser.parse_args()
app = QApplication(sys.argv)
mainwindow = MainWindow(args)
#~ mainwindow.showFullScreen()
mainwindow.show()
sys.exit(app.exec_())
I tried to paste the minimal code. The thing is, I press the button nothing shows, although I used examples like this one PyQt5 - Can't play video using QVideoWidget to test if playing the video is ok, and these work. It's as if it is not adding the widget to the layout or something. Any idea what might be wrong?
I had to use QGraphicsView to achieve what I wanted, here is a fix:
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtMultimedia import *
from PyQt5.QtMultimediaWidgets import *
import glob
class MainWindow(QMainWindow):
def __init__(self):
super(MainWindow, self).__init__()
self.setWindowTitle('Navon test')
self.setWindowFlags(Qt.FramelessWindowHint)
# exit option for the menu bar File menu
self.exit = QAction('Exit', self)
self.exit.setShortcut('Ctrl+q')
# message for the status bar if mouse is over Exit
self.exit.setStatusTip('Exit program')
# newer connect style (PySide/PyQT 4.5 and higher)
self.exit.triggered.connect(app.quit)
self.setWindowIcon(QIcon('icon.ico'))
self.centralwidget = VideoPlayer()
self.setCentralWidget(self.centralwidget)
def keyPressEvent(self, QKeyEvent):
if QKeyEvent.key() == Qt.Key_Escape:
self.centralwidget.phaseQuit(2)
self.centralwidget.play()
class VideoPlayer(QWidget):
def __init__(self, parent=None):
super(VideoPlayer, self).__init__(parent)
self.mediaPlayer = QMediaPlayer(None, QMediaPlayer.VideoSurface)
self.videoItem = QGraphicsVideoItem()
self.videoItem.setSize(QSizeF(640, 480))
scene = QGraphicsScene(self)
graphicsView = QGraphicsView(scene)
scene.addItem(self.videoItem)
layout = QVBoxLayout()
layout.addWidget(graphicsView)
self.setLayout(layout)
self.mediaPlayer.setVideoOutput(self.videoItem)
self.counter = 0
def play(self):
if self.mediaPlayer.state() == QMediaPlayer.PlayingState:
pass
else:
self.mediaPlayer.setMedia(QMediaContent(QUrl.fromLocalFile(glob.glob("videos/*")[self.counter])))
self.mediaPlayer.play()
self.counter += 1
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
player = MainWindow()
player.show()
sys.exit(app.exec_())
In following code, when the button is clicked, I insert the plots into the tabs of an auinotebook in another frame.
for example, When I have multiple plots in the plt window, I can drag a notebook tab into the bottom (that results in displaying two plots). Later on when I delete the bottom tab, and try to go into other plots, I see a flicker like the closed tab is still there.
I guess the issue is with my on_nb_tab_close. Because, without that I was not able to notice any such problem.
I appreciate help. Code samples will be very useful. (wxpython version 2.812)
import wx
import wx.lib.agw.aui as aui
import matplotlib as mpl
from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as mplCanvas
def create_plotter(self):
try:
self.plotter.Show()
except AttributeError:
self.plotter =PlotFrame(self, 500, 500)
self.plotter.Show()
return self.plotter
class PlotFrame(wx.Frame):
def __init__(self, parent, height, width):
wx.Frame.__init__(self, None, size=(height,width), title="plts")
self.parent=parent
self.nb = aui.AuiNotebook(self)
self.Bind(aui.EVT_AUINOTEBOOK_PAGE_CLOSE, self.on_nb_tab_close, self.nb)
def AddPlotTab(self,name="plot"):
page = Plot(self.nb)
self.nb.AddPage(page,name)
return page
def on_nb_tab_close(self, evt):
print "tab close fired"
s=self.nb.GetSelection()
v=self.nb.RemovePage(s)
if not self.nb.GetPageCount():
self.on_Close(evt)
evt.Veto()
class Plot(wx.Panel):
def __init__(self, parent, id = -1, dpi = None, **kwargs):
wx.Panel.__init__(self, parent, id=id, **kwargs)
self.figure = mpl.figure.Figure(dpi=dpi)
self.canvas = mplCanvas(self, -1, self.figure) # wxPanel object containing plot
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(self.canvas,1,wx.EXPAND)
self.SetSizer(sizer)
class MainFrame(wx.Frame):
def __init__(self, parent):
wx.Frame.__init__(self, parent, title="Plotting test", size=(300, 300))
self.btn1 = wx.Button(self, -1, "Print 1")
self.Bind(wx.EVT_BUTTON, self.OnBtn1, self.btn1)
def OnBtn1(self, evt):
plotter=create_plotter(self)
page1 = plotter.AddPlotTab("case 1: first_plot")
page1.figure.gca().plot(range(10),range(10),'+')
page1.figure.gca().plot(range(10),range(10),'-',color='red')
page1.figure.canvas.draw()
if __name__ == '__main__':
APP = wx.App(False)
FRAME = MainFrame(None)
FRAME.Show()
APP.MainLoop()