I would like to remove the gap between my QListWidget items in my textureIconChart QListWidget. It is populated with items set with pixmap icons. I am using QListWidget set to a QHBoxLayout, which is set to a QVBoxLayout.
import maya.cmds as cmds
import os
import maya.OpenMayaUI as mui
from PySide2 import QtWidgets,QtCore,QtGui
import shiboken2
class texture_replacer():
def texture_linker_UI(self):
windowName = "name"
if cmds.window(windowName,exists = True):
cmds.deleteUI(windowName, wnd = True)
pointer = mui.MQtUtil.mainWindow()
parent = shiboken2.wrapInstance(long(pointer),QtWidgets.QWidget)
window = QtWidgets.QMainWindow(parent)
window.setObjectName(windowName)
window.setWindowTitle(windowName)
window.setMinimumSize(450,650)
window.setMaximumSize(600,400)
mainWidget = QtWidgets.QWidget()
window.setCentralWidget(mainWidget)
verticalLayout = QtWidgets.QVBoxLayout(mainWidget)
self.textureIconChartLayout = QtWidgets.QVBoxLayout()
textureIconsLayout = QtWidgets.QHBoxLayout()
self.textureIconChartLayout.addLayout(textureIconsLayout)
verticalLayout.addLayout(self.textureIconChartLayout)
self.textureIconChart = QtWidgets.QListWidget()
self.textureIconChart.setViewMode(QtWidgets.QListWidget.IconMode)
self.textureIconChart.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn)
self.textureIconChart.setDragEnabled(0)
self.textureIconChart.setMaximumWidth(290)
self.populateListWidget()
textureIconsLayout.addWidget(self.textureIconChart)
textureIconsLayout.setSpacing(0)
textureIconsLayout.setContentsMargins(0,0,0,0)
tr = texture_replacer()
tr.texture_linker_UI()
Related
I am attempting to create a field in a QWizardPage that the user can either click on and a popup window opens up (this would be a window with a map on that allows the user to pick 2 coordinates) or allows the user to input the coordinates themselves. Think along the lines of a file picker line where the user can either open the popup file browser or manually type in the file path.
The original command is QLineEdit.
You have to create a custom widget that for example shows a QDoubleSpinBox for latitude and another for longitude, in addition to a button that allows to display a map (for example using QML). And then the widget is added to QWizardPage like any other widget.
import os
import sys
from pathlib import Path
from PySide2.QtCore import Property, Signal, Slot, Qt, QUrl
from PySide2.QtWidgets import (
QApplication,
QDialog,
QDialogButtonBox,
QDoubleSpinBox,
QHBoxLayout,
QLabel,
QToolButton,
QVBoxLayout,
QWidget,
QWizard,
QWizardPage,
)
from PyQt5.QtPositioning import QGeoCoordinate
from PyQt5.QtQuickWidgets import QQuickWidget
CURRENT_DIRECTORY = Path(__file__).resolve().parent
class MapDialog(QDialog):
def __init__(self, geo_widget):
super().__init__(geo_widget)
self.setWindowTitle("Map")
self.map_widget = QQuickWidget(resizeMode=QQuickWidget.SizeRootObjectToView)
self.map_widget.rootContext().setContextProperty("controller", geo_widget)
filename = os.fspath(CURRENT_DIRECTORY / "main.qml")
url = QUrl.fromLocalFile(filename)
self.map_widget.setSource(url)
button_box = QDialogButtonBox()
button_box.setOrientation(Qt.Horizontal)
button_box.setStandardButtons(QDialogButtonBox.Cancel | QDialogButtonBox.Ok)
lay = QVBoxLayout(self)
lay.addWidget(self.map_widget)
lay.addWidget(button_box)
button_box.accepted.connect(self.accept)
button_box.rejected.connect(self.reject)
class GeoWidget(QWidget):
coordinate_changed = Signal(name="coordinateChanged")
def __init__(self, parent=None):
super().__init__(parent)
self._coordinate = QGeoCoordinate(0, 0)
self._lat_spinbox = QDoubleSpinBox(
minimum=-90.0, maximum=90.0, valueChanged=self.handle_value_changed
)
self._lng_spinbox = QDoubleSpinBox(
minimum=-180.0, maximum=180.0, valueChanged=self.handle_value_changed
)
self.btn = QToolButton(text="map", clicked=self.handle_clicked)
self.map_view = MapDialog(self)
lay = QHBoxLayout(self)
lay.addWidget(QLabel("Latitude:"))
lay.addWidget(self._lat_spinbox)
lay.addWidget(QLabel("Longitude:"))
lay.addWidget(self._lng_spinbox)
lay.addWidget(self.btn)
#Property(QGeoCoordinate, notify=coordinate_changed)
def coordinate(self):
return self._coordinate
#coordinate.setter
def coordinate(self, coordinate):
if self.coordinate == coordinate:
return
self._coordinate = coordinate
self.coordinate_changed.emit()
def handle_value_changed(self):
coordinate = QGeoCoordinate(
self._lat_spinbox.value(), self._lng_spinbox.value()
)
self.coordinate = coordinate
#Slot(QGeoCoordinate)
def update_from_map(self, coordinate):
self.coordinate = coordinate
self._lat_spinbox.setValue(self.coordinate.latitude())
self._lng_spinbox.setValue(self.coordinate.longitude())
def handle_clicked(self):
self.map_view.exec_()
class WizardPage(QWizardPage):
def __init__(self, parent=None):
super().__init__(parent)
self.geo_widget1 = GeoWidget()
self.geo_widget2 = GeoWidget()
self.registerField("coordinate1", self.geo_widget1, b"coordinate")
self.registerField("coordinate2", self.geo_widget2, b"coordinate")
lay = QVBoxLayout(self)
lay.addWidget(self.geo_widget1)
lay.addWidget(self.geo_widget2)
def main():
app = QApplication(sys.argv)
w = QWizard()
page = WizardPage()
w.addPage(page)
w.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main()
import QtLocation 5.15
import QtQuick 2.15
Item {
width: 400
height: 400
Map {
id: map
anchors.fill: parent
zoomLevel: 14
MouseArea {
id: mouse
anchors.fill: parent
onClicked: controller.update_from_map(map.toCoordinate(Qt.point(mouse.x, mouse.y)))
}
plugin: Plugin {
name: "osm"
}
}
}
I got two py files. One has the main window with a QStackedWidget inside, the setCurrentWidget is set according to a condition. The other file has a widget which is dynamically added into the stacked widget and set as current widget when a button in the main window is clicked.
The widget in the second file has a dialog with a button in it. What I'm trying to do is, on clicking the button inside the dialog, the dialog should be closed and the setCurrentWidget is set according to the condition and the widget is removed from the stacked widget.
Here is what I've tried:
mainwindow.py
import sys
import os
import pathlib
from PySide2.QtWidgets import *
from PySide2 import *
from PySide2.QtCore import *
from PySide2.QtGui import *
list1 = ["item1", "item2", "item3"]
class MainWindow(QWidget):
def __init__(self):
super(MainWindow, self).__init__()
self.resize(400, 300)
self.toolbar = QWidget()
self.toolbar.setFixedHeight(30)
self.toolbar.setStyleSheet("background: grey;")
self.button = QPushButton("Click here!")
t_layout = QHBoxLayout()
t_layout.setMargin(0)
t_layout.addWidget(self.button)
self.toolbar.setLayout(t_layout)
self.p1_label = QLabel("Such empty!")
self.p1_label.setStyleSheet("font-size: 30px;")
self.p1_label.setAlignment(Qt.AlignCenter)
self.p2_widget = QWidget()
self.p2_widget.setStyleSheet("background: orange;")
self.sw = QStackedWidget()
self.sw.addWidget(self.p1_label)
self.sw.addWidget(self.p2_widget)
if not list1:
self.sw.setCurrentWidget(self.p1_label)
else:
self.sw.setCurrentWidget(self.p2_widget)
self.mw_layout = QVBoxLayout()
self.mw_layout.addWidget(self.toolbar)
self.mw_layout.addWidget(self.sw)
self.setLayout(self.mw_layout)
def switch_widget():
import widget_test
p3 = widget_test.widget()
self.sw.addWidget(p3)
self.sw.setCurrentWidget(p3)
self.button.clicked.connect(switch_widget)
def switch_back(self):
import widget_test
p3 = widget_test.widget()
mwin = MainWindow()
sw_ = mwin.sw
sw_.removeWidget(p3)
p1 = mwin.p1_label
p2 = mwin.p2_widget
if not list1:
sw_.setCurrentWidget(p1)
else:
sw_.setCurrentWidget(p2)
if __name__ == '__main__':
app = QApplication(sys.argv)
mw = MainWindow()
mw.show()
sys.exit(app.exec_())
widget.py
import sys
import os
import pathlib
import datetime
from PySide2.QtWidgets import *
from PySide2 import *
from PySide2.QtCore import *
from PySide2.QtGui import *
class widget(QWidget):
def __init__(self):
super(widget, self).__init__()
self.setStyleSheet("background: teal;")
widget_label = QLabel("fluid dynamics is cool")
show_pop_up = QPushButton("show pop up")
pop_up = QDialog(self)
pop_up_label = QLabel("click below to, hopefully, get outta here")
get_outta_here = QPushButton("get outta here")
pop_up_layout = QVBoxLayout()
pop_up_layout.addWidget(pop_up_label)
pop_up_layout.addWidget(get_outta_here)
pop_up.setLayout(pop_up_layout)
def show_popup():
pop_up.show()
def get_out():
from main_test import MainWindow
MainWindow.switch_back(self)
pop_up.reject()
get_outta_here.clicked.connect(get_out)
show_pop_up.clicked.connect(show_popup)
widget_layout = QVBoxLayout()
widget_layout.addWidget(widget_label)
widget_layout.addWidget(show_pop_up)
self.setLayout(widget_layout)
I could merge the code together and make it work but I'm trying to keep the directory clean.
There is a lot going on here, but let's break it down.
The main problem seems to be juggling between modules. Eventhough it might seem appealing to import the modules back and forth, it doesn't really work. What you need to look for, is the built-in Signals module that you can utilize.
Another bigger problem is that you are re-assigning some attributes eventhough you really shouldn't. You also should revisit the condition you are using to assign the .setCurrentWidget. Currently the condition reads as if list1 doesn't exist, do this. Else, do the other. Also, switch_widget should be outside of the def __init__(self):.
I rewrote some parts of the code to make it work with signals as an example for you.
mainwindow.py
import sys
import os
import pathlib
from PySide2.QtWidgets import *
from PySide2 import *
from PySide2.QtCore import *
from PySide2.QtGui import *
from widget_test import widget
list1 = ["item1", "item2", "item3"]
class MainWindow(QWidget):
def __init__(self):
super(MainWindow, self).__init__()
self.resize(400, 300)
self.toolbar = QWidget()
self.toolbar.setFixedHeight(30)
self.toolbar.setStyleSheet("background: grey;")
self.button = QPushButton("Click here!")
t_layout = QHBoxLayout()
t_layout.setMargin(0)
t_layout.addWidget(self.button)
self.toolbar.setLayout(t_layout)
self.p1_label = QLabel("Such empty!")
self.p1_label.setStyleSheet("font-size: 30px;")
self.p1_label.setAlignment(Qt.AlignCenter)
self.p2_widget = QWidget()
self.p2_widget.setStyleSheet("background: orange;")
self.p3 = None
self.sw = QStackedWidget()
self.sw.addWidget(self.p1_label)
self.sw.addWidget(self.p2_widget)
if not list1:
self.sw.setCurrentWidget(self.p1_label)
else:
self.sw.setCurrentWidget(self.p2_widget)
self.mw_layout = QVBoxLayout()
self.mw_layout.addWidget(self.toolbar)
self.mw_layout.addWidget(self.sw)
self.setLayout(self.mw_layout)
self.button.clicked.connect(self.switch_widget)
def switch_widget(self):
self.p3 = widget()
self.p3.update_signal.connect(self.switch_back)
self.sw.addWidget(self.p3)
self.sw.setCurrentWidget(self.p3)
def switch_back(self):
self.sw.removeWidget(self.p3)
if list1:
self.sw.setCurrentWidget(self.p1_label)
else:
self.sw.setCurrentWidget(self.p2_widget)
if __name__ == '__main__':
app = QApplication(sys.argv)
mw = MainWindow()
mw.show()
sys.exit(app.exec_())
widget.py
import sys
import os
import pathlib
import datetime
from PySide2.QtWidgets import *
from PySide2 import *
from PySide2.QtCore import *
from PySide2.QtGui import *
from PySide2.QtCore import Signal
class widget(QWidget):
update_signal = Signal()
def __init__(self):
super(widget, self).__init__()
self.setStyleSheet("background: teal;")
widget_label = QLabel("fluid dynamics is cool")
show_pop_up = QPushButton("show pop up")
pop_up = QDialog(self)
pop_up_label = QLabel("click below to, hopefully, get outta here")
get_outta_here = QPushButton("get outta here")
pop_up_layout = QVBoxLayout()
pop_up_layout.addWidget(pop_up_label)
pop_up_layout.addWidget(get_outta_here)
pop_up.setLayout(pop_up_layout)
def show_popup():
pop_up.show()
def get_out():
self.update_signal.emit()
pop_up.reject()
get_outta_here.clicked.connect(get_out)
show_pop_up.clicked.connect(show_popup)
widget_layout = QVBoxLayout()
widget_layout.addWidget(widget_label)
widget_layout.addWidget(show_pop_up)
self.setLayout(widget_layout)
Finally, check Python coding conventions for naming and other "minor" details.
How can I make it so the icon of a QListView's item resizes when i change the slider? It appears to resize the item but not it's icon.
I tried calling both of these, neither of them worked. I would ideally like to not call setGridSize since that causes the widget to ignore the setSpacing(5) which i intend on using.
self.uiListView.setGridSize(iconSize)
self.uiListView.setIconSize(iconSize)
import os, sys, re
from Qt import QtWidgets, QtGui, QtCore
from . import StyleUtils
values = ['MomBod','Colonel','Tater','Tot','Ginger','Donut','Sport','LaLa','Itchy','Bruiser','Cotton','Cumulus','Toodles','Salt','Ghoulie','Cat','Dirty','Harry','Buckeye','Flyby','Swiss','Miss','Buddy','Pecan','Sunny','Jet','Thor','Gingersnap','Cuddle','Pig','Turkey','Foxy','Mini','Me','Dolly','Stud','Music','Man','Barbie','Munchkin','Bubba','Hammer','Twizzler','Bebe']
class ViewerWidget(QtWidgets.QWidget):
def __init__(self):
QtWidgets.QWidget.__init__(self)
self.resize(500,500)
self.uiIconSize = QtWidgets.QSlider(QtCore.Qt.Horizontal)
self.uiIconSize.setRange(32,256)
self.uiIconSize.setValue(128)
self.uiIconSize.setMinimumWidth(100)
self.viewerModel = QtGui.QStandardItemModel()
self.viewerProxyModel = QtCore.QSortFilterProxyModel()
self.viewerProxyModel.setSourceModel(self.viewerModel)
self.uiListView = QtWidgets.QListView()
self.uiListView.setSpacing(5)
self.uiListView.setMovement(QtWidgets.QListView.Static)
self.uiListView.setViewMode(QtWidgets.QListView.IconMode)
self.uiListView.setLayoutMode(QtWidgets.QListView.Batched)
self.uiListView.setBatchSize(100)
self.uiListView.setFlow(QtWidgets.QListView.LeftToRight)
self.uiListView.setWrapping(True)
self.uiListView.setResizeMode(QtWidgets.QListView.Adjust)
self.uiListView.setDragEnabled(False)
self.uiListView.setUniformItemSizes(True)
self.uiListView.setIconSize(self.getIconSize())
self.uiListView.setSelectionMode(QtWidgets.QListView.ExtendedSelection)
self.uiListView.setModel(self.viewerProxyModel)
# main layout
self.layout = QtWidgets.QVBoxLayout()
self.layout.setContentsMargins(0,0,0,0)
self.layout.setSpacing(0)
self.layout.addWidget(self.uiListView)
self.layout.addWidget(self.uiIconSize)
self.setLayout(self.layout)
# Signals
self.uiIconSize.valueChanged.connect(self.setItemSize)
# Init
self.populateModel()
def getIconSize(self):
return QtCore.QSize(self.uiIconSize.value(), self.uiIconSize.value())
def setItemSize(self):
iconSize = self.getIconSize()
# self.uiListView.setGridSize(iconSize)
self.uiListView.setIconSize(iconSize)
def populateModel(self):
model = self.viewerModel
model.clear()
icon = QtGui.QIcon('C:/Users/jmartini/Desktop/image.png')
for x in values:
newItem = QtGui.QStandardItem(x)
newItem.setData(icon, role=QtCore.Qt.DecorationRole)
model.appendRow(newItem)
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
ex = ViewerWidget()
ex.show()
sys.exit(app.exec_())
I discovered this is a result of my icon's native size being 64x64. Qt will not resize the icon to be larger than it's original size. It will only resize the icon to be of a smaller size.
self.uiListView.setIconSize(QtCore.QSize(64,64))
I am trying to dynamically update a menu with new items when I add new items via the form into Qsettings. For example, if you open my code and click the button and then click "new" it will open a QLineEdit with a button. When the button is clicked the list data gets stored via Qsettings.
I'd like to be able to update the menu somehow to show the items without restarting. I tried some things like calling repaint and update in a few areas with no luck.
Here is my code, I slimmed it down the best that I could for the example.
import functools
import sys
from PyQt5 import QtCore
from PyQt5.QtGui import QIcon
from PyQt5.QtWidgets import QWidget, QPushButton, QHBoxLayout, \
QVBoxLayout, QLineEdit,QApplication, QWidgetAction, QTextBrowser, QAction, QMenu
class MainWindow(QWidget):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.layout = QHBoxLayout()
self.menu_action = QAction(QIcon("icon.png"),"New", self)
self.menu_btn = QPushButton()
self.menu = MyMenu("Menu", self.menu_btn)
self.add_menu = self.menu.addMenu(QIcon("icon.png"), "Menu")
self.add_menu.addAction(self.menu_action)
self.menu_btn.setMenu(self.menu)
self.textBox = QTextBrowser(self)
action = QWidgetAction(self.menu_btn)
action.setDefaultWidget(self.textBox)
self.menu_btn.menu().addAction(action)
settings = QtCore.QSettings('test_org', 'my_app')
self.new_items = settings.value('new_item', [])
print('%s' % self.new_items)
for item in self.new_items:
self.create_action = QAction(QIcon("icon.png"), item[0], self)
self.create_action.setData(item)
self.add_menu.addAction(self.create_action)
self.create_action.triggered.connect(functools.partial(self.menu_clicked, self.create_action))
self.layout.addWidget(self.menu_btn)
self.setLayout(self.layout)
self.menu_action.triggered.connect(self.open_window)
def open_window(self):
self.create_menu_item = Create_Menu_Item()
self.create_menu_item.show()
def menu_clicked(self, item):
itmData = item.data()
print(itmData)
class Create_Menu_Item(QWidget):
def __init__(self, parent=None):
super(Create_Menu_Item, self).__init__(parent)
self.resize(200, 195)
self.layout = QVBoxLayout()
self.form = QLineEdit()
self.btn = QPushButton()
self.layout.addWidget(self.form)
self.layout.addWidget(self.btn)
self.btn.clicked.connect(self.save_new_item)
self.setLayout(self.layout)
def save_new_item(self):
settings = QtCore.QSettings('test_org', 'my_app')
self.new_item = settings.value('new_item', [])
self.new_item.append([self.form.text()])
settings.setValue('new_item', self.new_item)
print(self.new_item)
print('saved!')
class MyMenu(QMenu):
def event(self,event):
if event.type() == QtCore.QEvent.Show:
self.move(self.parent().mapToGlobal(QtCore.QPoint(0,0))-QtCore.QPoint(0,self.height()))
return super(MyMenu,self).event(event)
if __name__ == '__main__':
app = QApplication(sys.argv)
w = MainWindow()
w.show()
app.exec_()
Anyone have any ideas? Thanks.
You can create a for loop to access the list.
Bare in mind it is a list of lists so a nested for loop is neccessary
def save_new_item(self):
settings = QtCore.QSettings('test_org', 'my_app')
self.new_item = settings.value('new_item', [])
self.new_item.append([self.form.text()])
settings.setValue('new_item', self.new_item)
print(self.new_item)
print('saved!')
# Add new menu items..
for x in self.new_item:
for y in x:
print(y)
The above will keep adding the WHOLE list of items every time you add a new item..
To just add the newest item, this is all you need (the last item added to the list)
w.add_menu.addAction(self.new_item[0][-1])
so
def save_new_item(self):
settings = QtCore.QSettings('test_org', 'my_app')
self.new_item = settings.value('new_item', [])
self.new_item.append([self.form.text()])
settings.setValue('new_item', self.new_item)
print(self.new_item)
print('saved!')
#ADD last item in the list
w.add_menu.addAction(self.new_item[0][-1])
I want to create a little Filebrowser as described here, but by using PyQt5: Youtube-Video-Description
So far the Layout is working fine. Now I would like to implement the function that the files show up on the left QColumnView. Meaning the files of the clicked folder in the QTreeView can be seen on the right File-QColumnView. I don't get the point of how to create the right signal to set the pathindex for the QFileSystemModel of the QColumnView. Besides, it would be nicer if i could only show one (the name) column of the Folder-QTreeView.
Here is the code for the Browser:
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import QTreeView, QFileSystemModel, QApplication, QColumnView, QDockWidget, QMainWindow, QTextEdit
from PyQt5.QtCore import QDir, Qt
rootpath = QDir.currentPath()
class Browser(QMainWindow):
def __init__(self):
super(Browser, self).__init__()
self.createDockWindows()
self.textEdit = QTextEdit()
self.setCentralWidget(self.textEdit)
def createDockWindows(self):
dock = QDockWidget("Folders", self)
dock.setAllowedAreas(Qt.LeftDockWidgetArea | Qt.RightDockWidgetArea)
#Code to Create FileView Colums and FolderTree
self.FileView = QtWidgets.QColumnView()
self.FileView.setGeometry(QtCore.QRect(240, 10, 291, 281))
self.FolderTree = QtWidgets.QTreeView()
self.FolderTree.setGeometry(QtCore.QRect(10, 10, 221, 281))
FolderTree = self.FolderTree
#FolderTree.hidecolumn(1),... ?? to show only name column
#include FolderTree to a Dock at the left side
dock.setWidget(FolderTree)
self.addDockWidget(Qt.LeftDockWidgetArea, dock)
#set the model and rootpath for filling the FolderTree from self.ui
dirmodel = QFileSystemModel()
#set filter to show only folders
dirmodel.setFilter(QDir.NoDotAndDotDot | QDir.AllDirs)
dirmodel.setRootPath(rootpath)
#filemodel and filter for only files on right side
filemodel = QFileSystemModel()
filemodel.setFilter(QDir.NoDotAndDotDot | QDir.Files)
filemodel.setRootPath(rootpath)
FolderView = self.FolderTree
FolderView.setModel(dirmodel)
FolderView.setRootIndex(dirmodel.index(rootpath))
FileView = self.FileView
FileView.setModel(filemodel)
dock = QDockWidget("Files", self)
dock.setWidget(FileView)
self.addDockWidget(Qt.RightDockWidgetArea, dock)
#important lines for the connection, which does not work
self.FolderTree.clicked['QModelIndex'].connect(self.setpathonclick)
def setpathonclick(self):
currentpathindex = self.FolderTree.currentIndex()
self.FileView.setCurrentIndex(currentpathindex)
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
w = Browser()
w.resize(640, 480)
w.show()
sys.exit(app.exec_())
The last 12 lines are the important lines for the onclick connection of FolderTree and FileOverView.
You need to set the root index on the column-view:
filemodel = QFileSystemModel()
filemodel.setFilter(QDir.NoDotAndDotDot | QDir.Files)
filemodel.setRootPath(rootpath)
...
FileView = self.FileView
FileView.setModel(filemodel)
FileView.setRootIndex(filemodel.index(rootpath))
and then do more or less the same thing in the click handler:
...
self.FolderTree.clicked.connect(self.setpathonclick)
def setpathonclick(self, index):
rootpath = self.FolderTree.model().filePath(index)
filemodel = self.FileView.model()
filemodel.setRootPath(rootpath)
self.FileView.setRootIndex(filemodel.index(rootpath))