I don't know why but i can't move a button using Pyside2.
I named a button Lina and i tried to move it using :
self.__ButtonLina.move(400,400)
but it doesn't work, maybe i place this line in the wrong place in the code ?
Here is the code: (Lina's button is in the last tab)
# -*- coding: utf-8 -*-
import sys
from PySide2 import QtCore, QtGui
from PySide2.QtWidgets import *
from PySide2.QtGui import *
# orange Continental rgb(255, 128, 0)
class Dialog(QDialog):
def __init__(self, parent=None):
QDialog.__init__(self,parent)
# Les champs
self.__champTexteNomAuteur = QLineEdit("")
self.__champTextePrenomAuteur = QLineEdit("")
self.__champDateNaissanceAuteur = QDateEdit()
self.__champDateNaissanceAuteur.setCalendarPopup(True)
self.__champTexteTitreLivre = QLineEdit("")
self.__champDatePublication = QDateEdit()
self.__champDatePublication.setCalendarPopup(True)
self.__ButtonLina = QPushButton("Lina")
self.__ButtonLina.setMaximumWidth(145)
self.__ButtonLina.move(400,400)#------<----here is the problem
self.__ButtonLina.setStyleSheet("background-color: rgb(255, 128, 0);")
# Les widgets
self.__widgetAuteur = QWidget()
self.__widgetLivre = QWidget()
self.__widget1 = QWidget()
self.__widget2 = QWidget()
self.__Tools = QWidget()
self.__widget1.setStyleSheet("background-color: black;");
# Les layouts des onglets
self.__layoutTools = QFormLayout()
self.__layoutTools.addRow(self.__ButtonLina)
self.__Tools.setLayout(self.__layoutTools)
self.__layoutAuteur = QFormLayout()
self.__widgetAuteur.setLayout(self.__layoutAuteur)
# La boîte à onglets
self.__tabWidget = QTabWidget()
self.__tabWidget.addTab(self.__widgetAuteur, " Single Simulation ")
self.__tabWidget.addTab(self.__widgetLivre, " Batch Simulation ")
self.__tabWidget.addTab(self.__widget1, " Vehicule Simulation Tool ")
self.__tabWidget.addTab(self.__widget2, " Simulation ")
self.__tabWidget.addTab(self.__Tools, " Tools ")
# Le layout final
self.__mainLayout = QVBoxLayout()
self.__mainLayout.addWidget(self.__tabWidget)
self.setLayout(self.__mainLayout)
self.resize(1200,800)
self.setWindowTitle('VSS Vehicule Simulation Suite')
self.setStyleSheet("color: black;"
"background-color: black");
app = QApplication(sys.argv)
dialog = Dialog()
dialog.exec_()
if you have any idea it could be cool !
The layouts are used to manage the position and size of the widgets that it handles, in your case the position of the __ButtonLina is handled by __layoutTools, therefore the position you set manually is not applied. So if you want to establish a fixed position you should not use a layout.
In this case the solution is to remove the layout and set __ButtonLina to __Tools as parent of __ButtonLina to __Tools
# ...
self.__widget1.setStyleSheet("background-color: black;");
# Set as parent of__ButtonLina to __Tools
# so that the position of __ButtonLina is relative to __Tools
self.__ButtonLina.setParent(self.__Tools)
# remove layout
# Les layouts des onglets
# self.__layoutTools = QFormLayout()
# self.__layoutTools.addRow(self.__ButtonLina)
# self.__ButtonLina.clicked.connect(Lina)
# self.__Tools.setLayout(self.__layoutTools)
self.__layoutAuteur = QFormLayout()
# ...
Related
I've a stacklayout in a qt5-python program with 3 pages.
I change the page by clicking on three icons and it works perfectly.
import sys
from PyQt5.QtCore import QSize, Qt
from PyQt5.QtGui import QIcon, QPixmap
from PyQt5.QtWidgets import (
QAction,
QApplication,
QHBoxLayout,
QLabel,
QMainWindow,
QPushButton,
QStackedLayout,
QVBoxLayout,
QWidget,
QStatusBar,
QToolBar,
)
### TESTING CLASS ###
from PyQt5.QtGui import QColor, QPalette
from PyQt5.QtWidgets import QWidget
class Color(QWidget):
def __init__(self, color):
super().__init__()
self.setAutoFillBackground(True)
palette = self.palette()
palette.setColor(QPalette.Window, QColor(color))
self.setPalette(palette)
### TESTING CLASS ###
I_INDEX_PAGE_DISC = 0
I_INDEX_PAGE_SONG = 1
I_INDEX_PAGE_INSTRUMENT = 2
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("Studio Diary")
self.setWindowIcon(QIcon("img/icon/icone_main_window.png"))
### IMPOSTA DIMENSIONE INTERFACCIA ###
self.resize(900, 300)
### CREA LA BARRA DEGLI STRUMENTI ###
tbMainToolBar = QToolBar("Studio Diary Toolbar")
tbMainToolBar.setIconSize(QSize(64, 64))
tbMainToolBar.setMovable(False)
self.addToolBar(tbMainToolBar)
lstButtonIcon = []
### CREA ICONA DISCO ###
icoDisc = QIcon()
icoDisc.addPixmap(QPixmap("img/icon/toolbar/icon_disc_on.png"))
icoDisc.addPixmap(QPixmap("img/icon/toolbar/icon_disc_sel.png"), QIcon.Disabled)
### CREA BOTTONE DISCO ###
bticDisc = QAction(icoDisc, "Dischi", self)
bticDisc.setStatusTip("Gestisci i dischi")
lstButtonIcon.append(bticDisc)
### CREA ICONA CANZONE ###
icoSong= QIcon()
icoSong.addPixmap(QPixmap("img/icon/toolbar/icon_song_on.png"))
icoSong.addPixmap(QPixmap("img/icon/toolbar/icon_song_sel.png"), QIcon.Disabled)
### CREA BOTTONE DISCO ###
bticSong = QAction(icoSong, "Canzoni", self)
bticSong.setStatusTip("Gestisci le canzoni")
lstButtonIcon.append(bticSong)
### CREA ICONA STRUMENTO ###
icoInstrument = QIcon()
icoInstrument.addPixmap(QPixmap("img/icon/toolbar/icon_instrument_on.png"))
icoInstrument.addPixmap(QPixmap("img/icon/toolbar/icon_instrument_sel.png"), QIcon.Disabled)
### CREA BOTTONE STRUMENTO ###
bticInstrument = QAction(icoInstrument, "Strumenti", self)
bticInstrument.setStatusTip("Gestisci gli strumenthi")
lstButtonIcon.append(bticInstrument)
### AGGIUNGI BOTTONE DISCO ###
bticDisc.triggered.connect(lambda lam_pageDisc: self.activateDiscPage(lstButtonIcon))
tbMainToolBar.addAction(bticDisc)
### AGGIUNGI BOTTONE CANZONE ###
bticSong.triggered.connect(lambda lam_pageSong: self.activateSongPage(lstButtonIcon))
tbMainToolBar.addAction(bticSong)
### AGGIUNGI BOTTONE CANZONE ###
bticInstrument.triggered.connect(lambda lam_pageInstrument: self.activateInstrumentPage(lstButtonIcon))
tbMainToolBar.addAction(bticInstrument)
### CREA IL LAYOUT GENERALE ###
bvloMainPageLayout = QVBoxLayout()
self.stacklayout = QStackedLayout()
bvloMainPageLayout.addLayout(self.stacklayout)
self.stacklayout.addWidget(Color("red"))
self.stacklayout.addWidget(Color("green"))
self.stacklayout.addWidget(Color("yellow"))
wgtBodyApp = QWidget()
wgtBodyApp.setLayout(bvloMainPageLayout)
self.setCentralWidget(wgtBodyApp)
self.setStatusBar(QStatusBar(self))
def buildDiscPage(self, strColor="red"):
bhloDiscPage = QVBoxLayout()
tvAlbumSong = TreeView()
bhloDiscPage.addWidget(tvAlbumSong)
bhloDiscPage.addWidget(QLabel("Song"))
def buildSongPage(self):
bhloSongPage = QHBoxLayout()
self.stacklayout.addWidget(QLabel("cyan"))
def buildInstrumentPage(self):
bhloSongPage = QHBoxLayout()
self.stacklayout.addWidget(QLabel("yellow"))
def activateDiscPage(self,mLstButtonIcon):
### IMPEDISCI CHE LA PAGINA VENGA RICHIAMATA SE E' GIA' STATA SELEZIONATA ###
bticCurrentButton = mLstButtonIcon[I_INDEX_PAGE_DISC]
blnIsEnabled = bticCurrentButton.isEnabled()
if blnIsEnabled == True:
self.buildDiscPage("green")
self.stacklayout.setCurrentIndex(I_INDEX_PAGE_DISC)
bticCurrentButton.setDisabled(True)
self.resetIconButtonActivationStatus(mLstButtonIcon,I_INDEX_PAGE_DISC)
def activateSongPage(self,mLstButtonIcon):
### IMPEDISCI CHE LA PAGINA VENGA RICHIAMATA SE E' GIA' STATA SELEZIONATA ###
bticCurrentButton = mLstButtonIcon[I_INDEX_PAGE_SONG]
blnIsEnabled = bticCurrentButton.isEnabled()
if blnIsEnabled == True:
self.buildSongPage()
self.stacklayout.setCurrentIndex(I_INDEX_PAGE_SONG)
bticCurrentButton.setDisabled(True)
self.resetIconButtonActivationStatus(mLstButtonIcon,I_INDEX_PAGE_SONG)
def activateInstrumentPage(self,mLstButtonIcon):
### IMPEDISCI CHE LA PAGINA VENGA RICHIAMATA SE E' GIA' STATA SELEZIONATA ###
bticCurrentButton = mLstButtonIcon[I_INDEX_PAGE_INSTRUMENT]
blnIsEnabled = bticCurrentButton.isEnabled()
if blnIsEnabled == True:
self.buildInstrumentPage()
self.stacklayout.setCurrentIndex(I_INDEX_PAGE_INSTRUMENT)
mLstButtonIcon[I_INDEX_PAGE_INSTRUMENT].setDisabled(True)
self.resetIconButtonActivationStatus(mLstButtonIcon,I_INDEX_PAGE_INSTRUMENT)
### RESETTA LO STATUS DI ATTIVAZIONE DEI BOTTONI
# === riattiva tutti i bottoni tranne quello corrente ===
def resetIconButtonActivationStatus(self,mLstButtonIcon,mIntCurrent):
for iButton in range (len(mLstButtonIcon)):
btIcSingleButton = mLstButtonIcon [iButton]
if iButton != mIntCurrent:
btIcSingleButton.setEnabled(True)
appMain = QApplication(sys.argv)
winMain = MainWindow()
winMain.show()
appMain.exec_()
When I click on the icon I will open the relative page, using the method activatePage() that recall buildPage()
I would that the page content will be update.
For example: In a page I will query the database or in another one I will pass some parameters to the buildPage() function to change some elements or style in the page.
How should I modify these functions?
[edit]
0
This code works perfectly but I would like to know another thing about it.
I've a layout like the one in the screenshoot.
The treeview is created by a class that builds the tree by querying a database.
I would like to update it when I add a new album. Can I update only the treeview and not all the page (maybe separating in two layouts)? I need to do it in other page of the application so I would learn how to do it.
Everytime I click on the icon/button on the toolbar should I query the database to update the view? In other pages I could add some infos.
(see the image in the answers)
QStackedLayout works with "pages" which are reusable, just like a "tabbed" interface does (in fact, QTabWidget uses a private QStackedWidget, which is based on QStackedLayout).
Considering the fact that pages are reusable, your issue is that you're not actually switching to the pages, but you're continuously adding a new page every time.
While dynamic creation of pages is obviously possible, even for optimization purposes, in your case you don't need that since you only have 3 pages.
Since those 3 pages will probably have their own "static" layout, a better solution is to create separate subclasses for each page, which allows creating specific function to update the data whenever required. This is a far better approach than creating single functions that do almost the same thing when creating/switching pages, and you can have a single interface to access/set the data from and to each page.
This is a possible implementation:
from PyQt5 import QtCore, QtWidgets
class Disco(QtWidgets.QFrame):
def __init__(self):
super().__init__()
self.artista = QtWidgets.QLineEdit()
self.titolo = QtWidgets.QLineEdit()
layout = QtWidgets.QFormLayout(self)
layout.addRow('Artista', self.artista)
layout.addRow('Titolo', self.titolo)
def setData(self, data):
self.artista.setText(data.get('artista', ''))
self.titolo.setText(data.get('titolo', ''))
def getData(self):
return {'artista': self.artista.text(), 'titolo': self.titolo.text()}
class Canzoni(QtWidgets.QFrame):
def __init__(self):
super().__init__()
layout = QtWidgets.QVBoxLayout(self)
self.table = QtWidgets.QTableWidget(0, 2)
self.table.setHorizontalHeaderLabels(('Titolo', 'Durata'))
layout.addWidget(self.table)
self.addButton = QtWidgets.QPushButton('Aggiungi')
layout.addWidget(self.addButton)
self.addButton.clicked.connect(lambda:
self.table.insertRow(self.table.rowCount()))
def setData(self, data):
self.table.clearContents()
canzoni = data.get('canzoni', [])
self.table.setRowCount(len(canzoni))
for row, (titolo, durata) in enumerate(canzoni):
self.table.setItem(row, 0, QtWidgets.QTableWidgetItem(titolo))
durataItem = QtWidgets.QTableWidgetItem()
durataItem.setData(QtCore.Qt.DisplayRole, int(durata))
self.table.setItem(row, 1, durataItem)
def getData(self):
canzoni = []
for row in range(self.table.rowCount()):
canzoni.append([
self.table.item(row, 0).text(),
self.table.item(row, 1).data(QtCore.Qt.DisplayRole),
])
return {'canzoni': canzoni}
class Strumenti(QtWidgets.QFrame):
def __init__(self):
super().__init__()
layout = QtWidgets.QVBoxLayout(self)
self.table = QtWidgets.QTableWidget(0, 2)
layout.addWidget(self.table)
self.table.setHorizontalHeaderLabels(('Artista', 'Strumenti'))
self.table.verticalHeader().hide()
self.addButton = QtWidgets.QPushButton('Aggiungi')
layout.addWidget(self.addButton)
self.addButton.clicked.connect(lambda:
self.table.insertRow(self.table.rowCount()))
def setData(self, data):
self.table.clearContents()
strumenti = data.get('strumenti', [])
self.table.setRowCount(len(strumenti))
for row, (artista, strumento) in enumerate(strumenti):
self.table.setItem(row, 0, QtWidgets.QTableWidgetItem(artista))
self.table.setItem(row, 1, QtWidgets.QTableWidgetItem(strumento))
def getData(self):
strumenti = []
for row in range(self.table.rowCount()):
strumenti.append([
self.table.item(row, 0).text(),
self.table.item(row, 1).text(),
])
return {'strumenti': strumenti}
class MainWindow(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
self.stackWidget = QtWidgets.QStackedWidget()
self.setCentralWidget(self.stackWidget)
self.disco = Disco()
self.stackWidget.addWidget(self.disco)
self.canzoni = Canzoni()
self.stackWidget.addWidget(self.canzoni)
self.strumenti = Strumenti()
self.stackWidget.addWidget(self.strumenti)
self.pages = self.disco, self.canzoni, self.strumenti
self.loadAction = self.menuBar().addAction('Load')
self.loadAction.triggered.connect(self.loadData)
self.saveAction = self.menuBar().addAction('Save')
self.saveAction.triggered.connect(self.saveData)
for i, actionName in enumerate(('Disco', 'Canzoni', 'Strumenti')):
action = self.menuBar().addAction(actionName)
action.setData(i)
self.menuBar().triggered.connect(self.switchPageAction)
self.setStyleSheet('''
Disco {
background: red;
}
Canzoni {
background: green;
}
Strumenti {
background: yellow;
}
''')
self.switchPage(0)
def loadData(self):
data = {
'artista': 'Elio e le Storie Tese',
'titolo': 'Elio Samaga Hukapan Kariyana Turu',
'canzoni': [
['John Holmes', 206],
['Nubi di ieri sul nostro domani odierno', 253],
],
'strumenti': [
['Elio', 'Voci'],
['Rocco', 'Tastiere'],
]
}
for page in self.pages:
page.setData(data)
def saveData(self):
data = {}
for page in self.pages:
data.update(page.getData())
print(data)
def switchPageAction(self, action):
index = action.data()
if index is not None:
self.switchPage(index)
def switchPage(self, index):
self.stackWidget.setCurrentIndex(index)
for action in self.menuBar().actions():
action.setEnabled(action.data() != index)
Note that newly created rows in QTableWidget always return None for item() if no value has been set yet, so the saveFunction() above may throw exceptions, I obviously didn't add all required checkings; it's up to you to add proper data type checking.
Also consider that setting the palette on a parent widget propagates the palette to all its children too, including subchildren, that's why I used stylesheets instead, which allows using a proper selector for the class that requires specific properties; also note that I chose to use QFrame to simplify things, as QWidget doesn't directly support stylesheet drawing. Alternatively, you can use self.setAttribute(QtCore.Qt.WA_StyledBackground).
So I'm creating an image gallery browser in PYQT5.
I can choose a directory and load the image file icons in a scrollable widget like so:
If there is less than 20 or so images in the directory, it works fine. However when there's more than that the image labels for some reason don't show:
If I take a few of those images that aren't showing and put them into a new folder on their own, then try to load only those images, it works, only if the application hasn't already tried to load them before hand and failed, otherwise, the empty square happens again.
So this seems to me to be some sort of framework/memory limitation? Can anyone shed some light on this?
Here is my code:
# MainWindow Set-Up : Creating Widgets and Layouts
class ClassUi(object):
def setup(self, MainW):
MainW.setObjectName("MainW")
MainW.resize(400,500)
self.mainlayout = QtWidgets.QVBoxLayout()
self.centralwidget = QtWidgets.QWidget(MainW)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.centralwidget.sizePolicy().hasHeightForWidth())
self.centralwidget.setSizePolicy(sizePolicy)
self.centralwidget.setLayout(self.mainlayout)
MainW.setCentralWidget(self.centralwidget)
#direcwidget is a container widget for the top part of the program where a directory is chosen
self.direcwidget = QtWidgets.QWidget()
self.direclayout = QtWidgets.QGridLayout()
self.direcwidget.setLayout(self.direclayout)
self.mainlayout.addWidget(self.direcwidget)
self.opdirbut = QtWidgets.QPushButton() #Button that opens directory dialog when pressed
self.opdirbut.setText("Choose")
self.opdirbut.setFixedSize(50,50)
self.linepath = QtWidgets.QLineEdit() #Line Edit that displays current directory
self.linepath.setText(os.getcwd())
self.backpath = QtWidgets.QPushButton() #Button that changes directory to parent directory of the current one
self.backpath.setFixedSize(20,20)
self.backpath.setText("^")
#Positioning of widgets inside widget container direcwidget
self.direclayout.addWidget(self.opdirbut, 0,0, 2, 1)
self.direclayout.addWidget(self.linepath, 0,2, 1, 3)
self.direclayout.addWidget(self.backpath, 1,4, 1, 1)
#Scrollwidget is the area wherein a container widget widgetforscroll holds all image icons in a grid
self.scrollwidget = QtWidgets.QScrollArea()
self.mainlayout.addWidget(self.scrollwidget)
self.scrollwidget.setWidgetResizable(True)
self.scrollwidget.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn)
self.scrollgrid = QtWidgets.QGridLayout()
self.widgetforscroll = QtWidgets.QWidget()
self.widgetforscroll.setLayout(self.scrollgrid)
self.scrollwidget.setWidget(self.widgetforscroll)
#Contains logic of program
class MainWindow(QtWidgets.QMainWindow, ClassUi):
def __init__(self):
super().__init__()
self.setup(self)
#Counter variables for keeping track of where to layout items
self.picturerow = 0
self.picturecolumn = 0
self.howmany = 0
#Assigns class methods to directory buttons
self.opdirbut.clicked.connect(self.opdial)
self.backpath.clicked.connect(self.uppath)
# Each time this function is called, a new widget called newwidget is created containing "pic" in a pixmap label and a text label and layed out
# on the widgetforscroll widget through its scrollgrid layout. Each time the function is called, picture column increments by one at the end of the function
# when all the columns in a row are filled, picture column is reset to 0 and and picture row is incremented. Picture row and picture column are used in positioning
# the newwidgets in the scrollgrid.
def addpicture(self, pic):
if self.picturecolumn == 3:
self.picturecolumn = 0
self.picturerow += 1
self.howmany += 1
#newwidget is object of picwidg class containing pixmap and text label
newwidget = picwidg(self.howmany, pic)
#This function was not required to be created, it was only created for the purpose of the Qtimer singleshot implementation.
#The newwidget is being positioned on the scrollgrid layout here.
def addnewone(lyout,nw,rw,cl):
lyout.addWidget(nw, rw, cl)
QtCore.QTimer.singleShot(
self.howmany*500,
lambda sc=self.scrollgrid, nr = newwidget, ow = self.picturerow, mn=self.picturecolumn : addnewone(sc,nr,ow,mn)
)
#Incrementing column by 1 for the next time function is called
self.picturecolumn += 1
#This is the function connected to the choose dialog button. It opens a QFileDialog window which allows you to only choose a directory folder.
#When the folder is chosen:
# 1: The linepath text is set the to the new directory
# 2: Any previous picwidg objects are cleared from the scrollgrid layout
# 3: Picture column and picture row variables are reset for positioning
# 4: A for loop scans the new directory for files with .jpg or .png extensions
# 5: The addpicture method is called with the filename as the argument
def opdial(self):
dialogbox = dialog()
try:
os.chdir(dialogbox.getExistingDirectory(options=QtWidgets.QFileDialog.DontUseNativeDialog))
self.linepath.setText(os.getcwd())
for i in reversed(range(self.scrollgrid.count())):
widgetToRemove = self.scrollgrid.itemAt(i).widget()
# remove it from the layout list
self.scrollgrid.removeWidget(widgetToRemove)
# remove it from the gui
widgetToRemove.setParent(None)
self.picturecolumn =0
self.picturerow =0
self.howmany = 0
for a, b, c in os.walk(os.getcwd()):
for i in c:
if i[-4:].lower() == ".png" or i[-4:].lower() == ".jpg":
self.addpicture(i)
except:
pass
#This is the function for reaching the parent directory. It works very similar to the above function, the only difference
#being that instead of grabbing a new directory from a QFileDialog, the directory processed is taken from the current linepath text
#and goes to the parent directory instead, then removes widgets from the scrolllayout and adds new pictures to the scrolllayout
def uppath(self):
newpath = os.path.dirname(self.linepath.text())
os.chdir(newpath)
self.linepath.setText(newpath)
for i in reversed(range(self.scrollgrid.count())):
widgetToRemove = self.scrollgrid.itemAt(i).widget()
# remove it from the layout list
self.scrollgrid.removeWidget(widgetToRemove)
# remove it from the gui
widgetToRemove.setParent(None)
self.picturecolumn = 0
self.picturerow = 0
self.howmany = 0
for a, b, c in os.walk(os.getcwd()):
for i in c:
# print(i[-4:].lower())
if i[-4:].lower() == ".png" or i[-4:].lower() == ".jpg":
self.addpicture(i)
# This is the class where newwidget instances are created
# Here 2 labels are created, one for the image, one for the text and packed in a vertical layout
class picwidg(QtWidgets.QWidget):
whoshover = None
picwidglist =[]
def __init__(self, numb, pic):
super().__init__()
self.setMouseTracking(True)
self.numb = numb
self.pic = pic
picwidg.picwidglist.append(self)
SizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
newwidgetlayout = QtWidgets.QVBoxLayout()
self.setLayout(newwidgetlayout)
self.setSizePolicy(SizePolicy)
self.setMinimumSize(QtCore.QSize(115, 140))
self.setMaximumSize(QtCore.QSize(115, 140))
#Pic Label
self.newpic = QtWidgets.QLabel()
QtCore.QTimer.singleShot(self.numb*500, self.addingnewpic)
self.newpic.setScaledContents(True)
self.newpic.setSizePolicy(SizePolicy)
self.newpic.setGeometry(0, 0, 100, 100)
self.newpic.setStyleSheet("border:1px solid gray")
#Picture text label
self.newtext = QtWidgets.QLabel()
font_metrics = QtGui.QFontMetrics(self.font())
self.newtext.setAlignment(QtCore.Qt.AlignCenter)
elided_text = font_metrics.elidedText(pic, QtCore.Qt.ElideRight, 100)
self.newtext.setText(elided_text)
newwidgetlayout.addWidget(self.newpic)
newwidgetlayout.addWidget(self.newtext)
def addingnewpic(self):
self.newpic.setPixmap(QtGui.QPixmap(self.pic))
#Class for QFileDialog for selecting only directories
class dialog(QtWidgets.QFileDialog):
def __init__(self):
super().__init__()
self.setFileMode(QtWidgets.QFileDialog.DirectoryOnly)
self.setOption(QtWidgets.QFileDialog.DontUseNativeDialog, True)
self.setOption(QtWidgets.QFileDialog.ShowDirsOnly, False)
if __name__ == "__main__" :
import sys
app = QtWidgets.QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec_())
If you want to show a lot of QPixmap then it is not optimal to use a lot of QLabel, in that case it is better to use a QListView (or QListWidget) since it handles memory better.
In your code you add and remove QLabels but in the case of the model only items are added or removed and the view is repainted avoiding the excessive use of memory.
Considering the above I have implemented the following solution:
import os
from PyQt5 import QtCore, QtGui, QtWidgets
ICON_SIZE = 100
class StyledItemDelegate(QtWidgets.QStyledItemDelegate):
def initStyleOption(self, option, index):
super().initStyleOption(option, index)
option.text = option.fontMetrics.elidedText(
index.data(), QtCore.Qt.ElideRight, ICON_SIZE
)
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super().__init__(parent)
self.choose_btn = QtWidgets.QPushButton(
self.tr("Choose"), clicked=self.on_choose_btn_clicked
)
self.choose_btn.setFixedSize(50, 50)
self.path_le = QtWidgets.QLineEdit()
self.back_btn = QtWidgets.QPushButton(
self.tr("^"), clicked=self.on_back_btn_clicked
)
self.back_btn.setFixedSize(20, 20)
self.pixmap_lw = QtWidgets.QListWidget(
viewMode=QtWidgets.QListView.IconMode,
iconSize=ICON_SIZE * QtCore.QSize(1, 1),
movement=QtWidgets.QListView.Static,
resizeMode=QtWidgets.QListView.Adjust,
)
delegate = StyledItemDelegate(self.pixmap_lw)
self.pixmap_lw.setItemDelegate(delegate)
central_widget = QtWidgets.QWidget()
self.setCentralWidget(central_widget)
grid_layout = QtWidgets.QGridLayout(central_widget)
grid_layout.addWidget(self.choose_btn, 0, 0, 2, 1)
grid_layout.addWidget(self.path_le, 0, 1)
grid_layout.addWidget(self.back_btn, 1, 1, alignment=QtCore.Qt.AlignRight)
grid_layout.addWidget(self.pixmap_lw, 2, 0, 1, 2)
self.resize(640, 480)
self.timer_loading = QtCore.QTimer(interval=50, timeout=self.load_image)
self.filenames_iterator = None
#QtCore.pyqtSlot()
def on_choose_btn_clicked(self):
directory = QtWidgets.QFileDialog.getExistingDirectory(
options=QtWidgets.QFileDialog.DontUseNativeDialog
)
if directory:
self.start_loading(directory)
#QtCore.pyqtSlot()
def on_back_btn_clicked(self):
directory = os.path.dirname(self.path_le.text())
self.start_loading(directory)
def start_loading(self, directory):
if self.timer_loading.isActive():
self.timer_loading.stop()
self.path_le.setText(directory)
self.filenames_iterator = self.load_images(directory)
self.pixmap_lw.clear()
self.timer_loading.start()
#QtCore.pyqtSlot()
def load_image(self):
try:
filename = next(self.filenames_iterator)
except StopIteration:
self.timer_loading.stop()
else:
name = os.path.basename(filename)
it = QtWidgets.QListWidgetItem(name)
it.setIcon(QtGui.QIcon(filename))
self.pixmap_lw.addItem(it)
def load_images(self, directory):
it = QtCore.QDirIterator(
directory,
["*.jpg", "*.png"],
QtCore.QDir.Files,
QtCore.QDirIterator.Subdirectories,
)
while it.hasNext():
filename = it.next()
yield filename
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec_())
Is there a way to customize the default toolbar of a mayavi scene? I would like to delete some buttons as I don't need them (e.g. the save button). Here you can see which toolbar I am talking about:
The code is just an example code:
import os
os.environ['ETS_TOOLKIT'] = 'qt4'
from pyface.qt import QtGui, QtCore
from traits.api import HasTraits, Instance, on_trait_change
from traitsui.api import View, Item
from mayavi.core.ui.api import MayaviScene, MlabSceneModel, SceneEditor
from tvtk.pyface.api import DecoratedScene
from pyface.api import ImageResource
from pyface.action.api import Action
class MyCustomScene(DecoratedScene):
def _actions_default(self):
actions = [
Action(
image = ImageResource("path to image",
search_path = [self._get_image_path()],
),
tooltip = "blabla",
on_perform = self._save_snapshot,
)
]
actions.extend(DecoratedScene._actions_default(self))
return actions
#The actual visualization
class Visualization(HasTraits):
scene = Instance(MlabSceneModel, ())
#on_trait_change('scene.activated')
def update_plot(self):
# We can do normal mlab calls on the embedded scene.
self.scene.mlab.test_points3d()
# the layout of the dialog screated
view = View(Item('scene', editor=SceneEditor(scene_class=MyCustomScene),
height=250, width=300, show_label=False),
resizable=True # We need this to resize with the parent widget
)
################################################################################
# The QWidget containing the visualization, this is pure PyQt4 code.
class MayaviQWidget(QtGui.QWidget):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)
layout = QtGui.QVBoxLayout(self)
layout.setContentsMargins(0,0,0,0)
layout.setSpacing(0)
self.visualization = Visualization()
# The edit_traits call will generate the widget to embed.
self.ui = self.visualization.edit_traits(parent=self,
kind='subpanel').control
layout.addWidget(self.ui)
self.ui.setParent(self)
if __name__ == "__main__":
# Don't create a new QApplication, it would unhook the Events
# set by Traits on the existing QApplication. Simply use the
# '.instance()' method to retrieve the existing one.
app = QtGui.QApplication.instance()
container = QtGui.QWidget()
container.setWindowTitle("Embedding Mayavi in a PyQt4 Application")
# define a "complex" layout to test the behaviour
layout = QtGui.QGridLayout(container)
# put some stuff around mayavi
label_list = []
for i in range(3):
for j in range(3):
if (i==1) and (j==1):continue
label = QtGui.QLabel(container)
label.setText("Your QWidget at (%d, %d)" % (i,j))
label.setAlignment(QtCore.Qt.AlignHCenter|QtCore.Qt.AlignVCenter)
layout.addWidget(label, i, j)
label_list.append(label)
mayavi_widget = MayaviQWidget(container)
layout.addWidget(mayavi_widget, 1, 1)
container.show()
window = QtGui.QMainWindow()
window.setCentralWidget(container)
window.show()
# Start the main event loop.
app.exec_()
I think it is somewhere hidden in the MayaviScene. Maybe it is necessary to create a new class with a new scene or something like this?
You should check _actions_default for MayaviScene and for DecoratedScene to see how to create one of your own. The second one shows how to create a toolbar from scratch while the first one shows how your toolbar code interfaces with other components.
class MyCustomScene(DecoratedScene):
# …
def _actions_default(self):
actions = [
# add icons here
# …
]
return actions
Morning/Afternoon/Evening
I've hit a brick wall previously I was able to have a QLineEdit be able to give you autofill options such as:
Autofill (Can't embedded images so its a link)
Previously the values were sorted in a list and using QCompleter and QStringListModel this was possible.
Having moved my form that was all QLineEdits to now just a QTableWidget. I want to achieve the same effect as previous with QLineEdit where if you type in the field labaled "Fittings" it will preform as previous. The values that were before stored in a List are now in a SQL DB.
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtSql import *
import tkinter
import sqlite3
import sys
connection = sqlite3.connect("PriceList.db")
# Getting Screen info
root = tkinter.Tk()
root.withdraw()
def setup(uname):
global user
user = uname
# Layout
layout = QHBoxLayout()
right_side = QGridLayout()
right_side.setAlignment(Qt.AlignTop)
left_side = QVBoxLayout()
class QuotesWindow(QMainWindow):
def __init__(self, *args, **kwargs):
super(QuotesWindow, self).__init__(*args, **kwargs)
# Window Settings
self.setWindowTitle("Herpy - " + user)
self.setWindowIcon(QIcon("icon.png"))
self.showMaximized()
# Right Side Enter Quote
self.input_table()
right_side.addWidget(self.tableWidget)
# Mid Line
mid_line = QFrame()
mid_line.setFrameShape(QFrame.VLine)
mid_line.setFrameShadow(QFrame.Sunken)
# Left Side Details
acc_bt = QPushButton("Account")
left_side.addWidget(acc_bt)
# Who
who_box = QLineEdit()
who_box.setPlaceholderText("Name")
left_side.addWidget(who_box)
# Street
street_box = QLineEdit()
street_box.setPlaceholderText("Street")
left_side.addWidget(street_box)
# Town
town_box = QLineEdit()
town_box.setPlaceholderText("Town")
left_side.addWidget(town_box)
# County
county_box = QLineEdit()
county_box.setPlaceholderText("County")
left_side.addWidget(county_box)
# Postcode
postc_box = QLineEdit()
postc_box.setPlaceholderText("Postcode")
left_side.addWidget(postc_box)
# Telephone
telep_box = QLineEdit()
telep_box.setPlaceholderText("Telephone Number")
left_side.addWidget(telep_box)
# Seperator
left_line = QFrame()
left_line.setFrameShape(QFrame.HLine)
left_line.setFrameShadow(QFrame.Sunken)
left_side.addWidget(left_line)
# Author
q_author = QLineEdit()
q_author.setPlaceholderText(user)
q_author.setReadOnly(True)
left_side.addWidget(q_author)
# Placed By
placed_b = QLineEdit()
placed_b.setPlaceholderText("Placed By")
left_side.addWidget(placed_b)
# Placed With
placed_w = QLineEdit()
placed_w.setPlaceholderText("Placed With")
left_side.addWidget(placed_w)
# Reference
ref_input = QLineEdit()
ref_input.setPlaceholderText("Reference")
left_side.addWidget(ref_input)
# To Fill Space
left_side.addStretch(1)
# Layouts
layout.addLayout(left_side)
layout.addWidget(mid_line)
layout.addLayout(right_side)
# Shortcut
shortcut = QShortcut(QKeySequence("Shift+Return"), self)
#shortcut.activated.connect(self.new_input)
# Makes it fucking render
widget = QWidget()
widget.setLayout(layout)
self.setCentralWidget(widget)
self.show()
def input_table(self):
# Auto Fill for Fittings
model = QSqlTableModel()
model.select()
completer = QCompleter()
completer.setCompletionColumn(1)
#completer.setCaseSensitivity(CaseInsensitive)
#completer.setCompletionRole(QtCore.Qt.EditRole)
#Create table
headers = ["Fittings", "Quantity", "Price", "Total"]
self.tableWidget = QTableWidget()
self.tableWidget.setRowCount(50)
self.tableWidget.setColumnCount(4)
self.tableWidget.setItem(0,0, QTableWidgetItem("Cell (1,1)"))
self.tableWidget.move(0,0)
self.tableWidget.setColumnWidth(1, 80)
self.tableWidget.horizontalHeader().setSectionResizeMode(0, QHeaderView.Stretch)
#self.tableWidget.setSelectionBehavior(QAbstractItemView.SelectRows)
#self.tableWidget.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
self.tableWidget.setHorizontalHeaderLabels(headers)
Thanks in advance :) Sorry its a bit messy
Edit: Was marked a dupe and give sqlite3 table into QTableWidget, sqlite3, PyQt5
Can't see how it corresponds with my code, am I missing something?
Edit2: Changed text so its more understable
I'm able to display a QTextEdit widget and detect when the user changes the selected text. However, I'm unsure how to get the selected text and the integer values that represent the start and end locations of the selection measured as the number of characters from the beginning of the text field. Do I need to create a QTextCursor? I'd appreciate an example. Here is my current code:
import sys
from PySide.QtCore import *
from PySide.QtGui import *
class Form(QDialog):
def __init__(self, parent=None):
super(Form, self).__init__(parent)
self.setWindowTitle("My Form")
self.edit = QTextEdit("Type here...")
self.button = QPushButton("Show Greetings")
self.button.clicked.connect(self.greetings)
self.quit = QPushButton("QUIT")
self.quit.clicked.connect(app.exit)
self.edit.selectionChanged.connect(self.handleSelectionChanged)
layout = QVBoxLayout()
layout.addWidget(self.edit)
layout.addWidget(self.button)
layout.addWidget(self.quit)
self.setLayout(layout)
def greetings(self):
print ("Hello %s" % self.edit.text())
def handleSelectionChanged(self):
print ("Selection start:%d end%d" % (0,0)) # change to position & anchor
if __name__ == '__main__':
app = QApplication(sys.argv)
form=Form()
form.show()
sys.exit(app.exec_())
You can work with selection within QTextEdit via QTextCursor, yes. It has selectionStart and selectionEnd methods which you should use:
def handleSelectionChanged(self):
cursor = self.edit.textCursor()
print ("Selection start: %d end: %d" %
(cursor.selectionStart(), cursor.selectionEnd()))
Here is the start, en and ho to get the text.
cursor = self.edit.textCursor()
start = cursor.selectionStart()
end = cursor.selectionEnd()
self.lbl_status.setText('Selected Count: ' + str(end - start))
txt = self.edit.textCursor().selectedText()