After my previous problem, I have my widgets on my main window. But this lasts doesn't come with any data: the datagridview haven't columns and the treeview are invisible or without my hard coded items. Here's my code:
app.py
#!/usr/bin/env python
import sys
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QIcon
from PyQt5.QtWidgets import QApplication, qApp, QWidget, QMainWindow, QGridLayout, QMenuBar, QAction, QToolBar, QStatusBar
from views import Main
class TerraSoft(QMainWindow):
def __init__(self):
QMainWindow.__init__(self)
self.setWindowTitle('TerraSoft')
self.setWindowState(Qt.WindowMaximized)
exitAct = QAction(QIcon('exit24.png'), 'Exit', self)
exitAct.setShortcut('Ctrl+Q')
exitAct.triggered.connect(qApp.quit)
fileMenu = self.menuBar().addMenu('File')
fileMenu.addAction(exitAct)
toolbar = self.addToolBar('Main')
toolbar.addAction(exitAct)
main = Main()
self.setCentralWidget(main)
self.statusBar().showMessage('Bienvenue dans TerraSoft')
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = TerraSoft()
ex.show()
sys.exit(app.exec_())
.views.py
import sys
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QIcon
from PyQt5.QtWidgets import QApplication, QWidget, qApp, QAction, QSplitter, QMenuBar, QToolBar, QGridLayout, QStatusBar
from Family.views import FamilyTreeView
from Specie.views import EventsTableView
class Main(QWidget):
def __init__(self, *args):
QWidget.__init__(self, *args)
familyTreeView = FamilyTreeView(self)
eventsTableView = EventsTableView(self)
HSplitter = QSplitter(Qt.Horizontal)
HSplitter.addWidget(familyTreeView)
HSplitter.addWidget(eventsTableView)
grid = QGridLayout()
grid.addWidget(HSplitter)
self.setLayout(grid)
module: Family.views.py
import sys
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QStandardItemModel, QStandardItem
from PyQt5.QtWidgets import QApplication, QWidget, QTreeView
families = [
("Craspedocephalus", [
("puniceus", []),
("trigonocephalus", [])
]),
("Trimeresurus", [
("albolabris", [])
]),
("Elapidé", [])
]
class FamilyTreeView(QWidget):
"""description of class"""
def __init__(self, *args):
QWidget.__init__(self, *args)
self.familyList = QTreeView()
self.familyList.setMaximumWidth(300)
self.model = QStandardItemModel()
self.addItems(self.model, families)
self.familyList.setModel(self.model)
self.model.setHorizontalHeaderLabels([self.tr("Familles")])
def addItems(self, parent, elements):
for text, children in elements:
item = QStandardItem(text)
parent.appendRow(item)
if children:
self.addItems(item, children)
module: specie.views.py
import sys
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QStandardItemModel, QStandardItem
from PyQt5.QtWidgets import QApplication, QWidget, QTableWidget, QTreeView
class EventsTableView(QTableWidget):
"""description of class"""
def __init__(self, *args):
QTableWidget.__init__(self, *args)
self.eventsTable = QTableWidget()
self.eventsTable.setColumnCount(3)
self.eventsTable.setHorizontalHeaderLabels(('Date', 'Catégorie', 'Description'))
enter code here
The result of this code gives:
hope you can help me again,
thanks per advance !
Not really sure why you want to derive FamilyTreeView from QWidget. I worked out a solution deriving it from QTreeView, directly. Your addItems method works correctly, but I used invisibleRootItem member of QStandardItem as the upper parent (i.e. root).
class FamilyTreeView(QTreeView):
"""description of class"""
def __init__(self, *args):
QTreeView.__init__(self, *args)
the_model = QStandardItemModel()
the_model.setHorizontalHeaderLabels([self.tr("Familles")])
self.addItems(the_model.invisibleRootItem(), families)
self.setModel(the_model)
def addItems(self, parent, elements):
for text, children in elements:
item = QStandardItem(text)
parent.appendRow(item)
if children:
self.addItems(item, children)
Your EventsTableView class has some issues too. It inherits from QTableWidget (i.e. is a QTableWidget) but yet defines an inner QTableWidget, which is unnecessary. Here is a better version:
class EventsTableView(QTableWidget):
"""description of class"""
def __init__(self, *args):
QTableWidget.__init__(self, *args)
self.setColumnCount(3)
self.setHorizontalHeaderLabels(('Date', 'Catégorie', 'Description'))
Related
I have a problem with my python code, it's a QTablewidget with Qpushbuttons and Qline_edits inside each cell, We want a file path (after selecting this file from the file browser) to be written in the line edit when we click on its pushbutton and to store the output files so we can use them after.
from PyQt5.QtWidgets import (
QMainWindow,
QApplication,
QPushButton,
QFileDialog,
QGridLayout,
QLineEdit,
QTableWidget,
QHBoxLayout,
QWidget,
)
from PyQt5.QtCore import pyqtSlot
import sys
from functools import partial
global list_C
list_C=[]
class boxlayout(QWidget):
def __init__(self):
super(boxlayout,self).__init__()
layout=QHBoxLayout()
layout.setContentsMargins(0,0,0,0)
layout.setSpacing(0)
boxlayout.le=QLineEdit()
boxlayout.btn=QPushButton()
layout.addWidget(boxlayout.le)
layout.addWidget(boxlayout.btn)
self.setLayout(layout)
class Main(QMainWindow):
def __init__(self):
super().__init__()
centralWidget = QWidget()
self.setCentralWidget(centralWidget)
mainlayout = QGridLayout(centralWidget)
self.table = QTableWidget(self)
self.table.resize(640, 480)
self.table.setColumnCount(3)
self.table.setRowCount(4)
mainlayout.addWidget(self.table)
save_button=QPushButton('OK')
mainlayout.addWidget(save_button)
save_button.clicked.connect(self.save_as_list)
for i in range(4):
for j in range(3):
self.table.setCellWidget(i,j, boxlayout())
boxlayout.btn.clicked.connect(partial(self.open_dialog, boxlayout.le))
#pyqtSlot(QLineEdit)
def open_dialog(self, le: QLineEdit):
file_name = QFileDialog.getOpenFileName(
self,
"Open File",
"${HOME}",
"All Files (*)",
)
le.setText(file_name[0])
def save_as_list(self):
for i in range(4):
for j in range(3):
item=self.table.cellWidget(i,j).le.text()
list_C.append(item)
print(list_C) #output=['last le value','last le value',...]
if __name__ == "__main__":
app = QApplication(sys.argv)
main_gui = Main()
main_gui.show()
sys.exit(app.exec())
Here is a minimal example:
from PyQt5.QtWidgets import (
QMainWindow,
QApplication,
QPushButton,
QFileDialog,
QFrame,
QGridLayout,
QLineEdit,
)
from PyQt5.QtCore import pyqtSlot
import sys
from functools import partial
class Main(QMainWindow):
def __init__(self):
super().__init__()
top_frame = QFrame(self)
self.setCentralWidget(top_frame)
self.grid = QGridLayout(top_frame)
for i in range(10):
btn = QPushButton(top_frame)
le = QLineEdit(top_frame)
btn.clicked.connect(partial(self.open_dialog, le))
btn.setText("open file system dialog")
self.grid.addWidget(btn, i, 0)
self.grid.addWidget(le, i, 1)
#pyqtSlot(QLineEdit)
def open_dialog(self, le: QLineEdit):
file_name = QFileDialog.getOpenFileName(
self,
"Open File",
"${HOME}",
"All Files (*)",
)
le.setText(file_name[0])
if __name__ == "__main__":
app = QApplication(sys.argv)
main_gui = Main()
main_gui.show()
sys.exit(app.exec())
The key thing here is to pass the QLineEdit to the file selector method.
Here we are doing it with: lambda: self.open_dialog(le)
I found the icon of QPushButon is blurry when DPI scaling is enabled. Even if replaced by SVG, the icon is still blurred. Is there any way to make the icon clearer?
Here is the code:
# coding:utf-8
import os
import sys
from PyQt5.QtGui import QIcon
from PyQt5.QtWidgets import QApplication, QPushButton, QWidget
class Demo(QWidget):
def __init__(self):
super().__init__(parent=None)
self.button = QPushButton(' Shuffle all', self)
imagePath = "app/resource/images/random_play_all/Shuffle_normal.png"
self.button.setIcon(QIcon(imagePath))
self.button.move(self.width()//2-self.button.width() //
2, self.height()//2-self.button.height()//2)
if __name__ == '__main__':
os.environ["QT_ENABLE_HIGHDPI_SCALING"] = "0"
os.environ["QT_SCALE_FACTOR"] = '1.25'
app = QApplication(sys.argv)
demo = Demo()
demo.show()
app.exec_()
The running result is shown in the figure below
I solved this problem by rewriting QIconEngine and setting Qt.AA_UseHighDpiPixmaps flag.
# coding:utf-8
import os
import sys
from PyQt5.QtCore import QPoint, QRect, QSize, Qt
from PyQt5.QtGui import QIcon, QIconEngine, QImage, QPainter, QPixmap
from PyQt5.QtWidgets import QApplication, QPushButton, QWidget
class PixmapIconEngine(QIconEngine):
""" Pixmap icon engine """
def __init__(self, iconPath: str):
self.iconPath = iconPath
super().__init__()
def paint(self, painter: QPainter, rect: QRect, mode: QIcon.Mode, state: QIcon.State):
painter.setRenderHints(QPainter.Antialiasing |
QPainter.SmoothPixmapTransform)
painter.drawImage(rect, QImage(self.iconPath))
def pixmap(self, size: QSize, mode: QIcon.Mode, state: QIcon.State) -> QPixmap:
pixmap = QPixmap(size)
pixmap.fill(Qt.transparent)
self.paint(QPainter(pixmap), QRect(QPoint(0, 0), size), mode, state)
return pixmap
class Icon(QIcon):
def __init__(self, iconPath: str):
self.iconPath = iconPath
super().__init__(PixmapIconEngine(iconPath))
class Demo(QWidget):
def __init__(self):
super().__init__(parent=None)
self.button = QPushButton(' Shuffle all', self)
imagePath = "resource/images/random_play_all/Shuffle_normal.png"
self.button.setIcon(Icon(imagePath))
self.button.move(self.width()//2-self.button.width() //
2, self.height()//2-self.button.height()//2)
if __name__ == '__main__':
os.environ["QT_ENABLE_HIGHDPI_SCALING"] = "0"
os.environ["QT_SCALE_FACTOR"] = '1.25'
QApplication.setAttribute(Qt.AA_UseHighDpiPixmaps)
app = QApplication(sys.argv)
demo = Demo()
demo.show()
app.exec_()
Here is the result
I discovered that, in a class inheriting from QGraphicsItem and QObject, calling QGraphicsItem.setFlags() causes immediate, errorless crash in PyQt5. The following example demonstrates this
import sys
from PyQt5.QtCore import QObject, QRectF
from PyQt5.QtGui import QColor
from PyQt5.QtWidgets import QGraphicsItem, QGraphicsView, QGraphicsScene, QMainWindow, QApplication
class Item(QObject, QGraphicsItem):
def __init__(self):
QObject.__init__(self)
QGraphicsItem.__init__(self)
self.setFlags(QGraphicsItem.ItemIsSelectable | QGraphicsItem.ItemIsMovable |
QGraphicsItem.ItemSendsScenePositionChanges)
def boundingRect(self) -> QRectF:
return QRectF(0,0,50,50)
def paint(self, painter, option, widget=...) -> None:
painter.fillRect(self.boundingRect(), QColor('#555555'))
class View(QGraphicsView):
def __init__(self):
super().__init__()
self.resize(400, 300)
scene = QGraphicsScene(self)
scene.setSceneRect(0,0,self.width(),self.height())
self.setScene(scene)
def mousePressEvent(self, event) -> None:
QGraphicsView.mousePressEvent(self, event)
if event.isAccepted():
return
newitem = Item()
self.scene().addItem(newitem)
newitem.setPos(event.pos())
class ViewWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setCentralWidget(View())
if __name__ == '__main__':
app = QApplication(sys.argv)
widget = ViewWindow()
widget.show()
app.exec_()
The same code works fine with PySide2. Did I miss something there? I'm using Python 3.9.5 and PyQt5 5.15.4.
I am trying to figure out how to select and edit newly created folder. Here is a bit of code demonstrating it:
import os
import sys
from PyQt5.QtWidgets import (QApplication,
QMainWindow,
QLabel,
QLineEdit,
QPushButton,
QShortcut,
QFileSystemModel,
QTreeView,
QWidget,
QVBoxLayout,
QHBoxLayout,
QLayout,
QMenu,
QPlainTextEdit,
QSizePolicy,
QMessageBox,
QAbstractItemView)
from PyQt5.QtCore import QSize, Qt, QRect
from PyQt5.QtGui import QKeySequence
class FSView(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.setFixedSize(size.width()*1/4, size.height()*0.85)
self.model = QFileSystemModel()
self.model.setRootPath('')
self.model.setReadOnly(False)
self.tree = QTreeView()
self.tree.setContextMenuPolicy(Qt.CustomContextMenu)
self.tree.customContextMenuRequested.connect(self.openMenu)
self.tree.setModel(self.model)
self.tree.setAnimated(False)
self.tree.setIndentation(20)
self.tree.setDragDropMode(QAbstractItemView.InternalMove)
windowLayout = QVBoxLayout()
windowLayout.addWidget(self.tree)
self.setLayout(windowLayout)
def openMenu(self, position):
menu = QMenu()
menu.addAction('New folder', self.NewF)
menu.exec_(self.tree.viewport().mapToGlobal(position))
def NewF(self):
d = str(self.model.filePath(self.tree.currentIndex())) + '/New folder'
if not os.path.exists(d):
os.mkdir(d)
# correctIndex = self.tree.currentIndex() + 1 #not working
# self.tree.edit(correctIndex)
if __name__ == '__main__':
app = QApplication(sys.argv)
screen = app.primaryScreen()
size = screen.size()
ex = FSView()
ex.show()
sys.exit(app.exec_())
After creating the new folder, I would like it to be selected and in edit mode at same time (i.e.: self.tree.edit(correctIndex)).
I have checked some posts (here) but still have not managed to get the correct index.
Thanks for suggestions.
Using your code you must first obtain the QModelIndex using the index() method of QFileSystemModel passing it the path, and then call the setCurrentIndex() and edit() methods of QTreeView.
def NewF(self):
d = str(self.model.filePath(self.tree.currentIndex())) + '/New folder'
if not os.path.exists(d):
os.mkdir(d)
ix = self.model.index(d)
QTimer.singleShot(0, lambda ix=ix: self.tree.setCurrentIndex(ix))
QTimer.singleShot(0, lambda ix=ix: self.tree.edit(ix))
Or use the mkdir() method of QFileSystemModel as shown below:
def NewF(self):
ci = self.tree.currentIndex()
ix = self.model.mkdir(ci, "New folder")
QTimer.singleShot(0, lambda ix=ix : self.tree.setCurrentIndex(ix))
QTimer.singleShot(0, lambda ix=ix : self.tree.edit(ix))
I put a QLineEdit in form.ui, and I want to use CustomLabel to inheriance it. But there are both 2 QLineEdit(lines in form.ui and CustomLabel) in my mainwindow.
How should I deal with this situation?
Here is the image of my programme
Here is my code:
import sys
from PyQt5.QtWidgets import QApplication, QWidget, QPushButton, QLineEdit, QLabel
from PyQt5.QtGui import QIcon
from PyQt5.QtCore import pyqtSlot
import PyQt5.uic as uic
form_ui,_ =uic.loadUiType('form.ui')
print(type(form_ui))
class Mainwindow(QWidget,form_ui):
"""docstring for App"""
def __init__(self):
super(Mainwindow, self).__init__()
self.setupUi(self)
path_lineEdit = CustomLabel(self.lines)
class CustomLabel(QLineEdit):
def __init__(self,parent=None):
super(CustomLabel,self).__init__(parent)
# self.resize(parent.size())
def dragEnterEvent(self, e):
if e.mimeData().hasFormat('text/plain'):
e.accept()
else:
e.ignore()
def dropEvent(self, e):
self.setText('212'+e.mimeData().text())
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = Mainwindow()
ex.show()
sys.exit(app.exec_())