So, I am almost done with building my program that creates mipmaps. It will successfully upload an image of your choosing, and create mipmaps of that image, but now the last part is where I am stuck.
I now want for the the user to be able to save his or her mipmaps, but I am not sure how. I want them to be able to save it anywhere they want, and I have a feeling it will require a dialoq box, but I only know how to implement dialog boxes when opening items, not saving them.
Here is my code so far:
from __future__ import division
from PyQt4 import QtCore, QtGui, QtOpenGL
from PyQt4.QtGui import * #Used to import QPixmap. DO NOT REMOVE.
from PyQt4.QtCore import * #Used to import Qt.KeepAspectRation. DO NOT REMOVE.
import sys, os
import mmCreator
class MyApp(QtGui.QMainWindow, mmCreator.Ui_MainWindow):
def __init__(self, parent=None):
super(MyApp, self).__init__(parent)
self.setupUi(self)
self.btnSelect.clicked.connect(self.select_image)
self.btnConvert.clicked.connect(self.mipmap)
self.btnDownload.clicked.connect(self.download)
def select_image(self):
self.origImage.setAlignment(QtCore.Qt.AlignCenter)
self.origImage.clear()
global image
image = QtGui.QFileDialog.getOpenFileName(self,
"Select Image",
"",
"Image File (*.jpg *.png *.gif)")
global pixmap
pixmap = QPixmap(image)
scaledPixmap = pixmap.scaled(self.origImage.size(), Qt.KeepAspectRatio)
self.origImage.setPixmap(scaledPixmap)
self.origImage.show()
def mipmap(self):
self.mipMap.setAlignment(QtCore.Qt.AlignCenter)
#Create scaled versions of the source image.
pixmap = QPixmap(image)
global mipmaps
mipmaps = []
#Version 1 goes up to 1/16 of original size.
mipmaps.append(pixmap.scaledToWidth(pixmap.width() / 2))
mipmaps.append(pixmap.scaledToWidth(pixmap.width() / 4))
mipmaps.append(pixmap.scaledToWidth(pixmap.width() / 8))
mipmaps.append(pixmap.scaledToWidth(pixmap.width() / 16))
#Show the first mipmapped version of the image, at 75% label size.
scaledMipMap = mipmaps[0].scaled(self.mipMap.size() * (3/4), Qt.KeepAspectRatio)
self.mipMap.setPixmap(scaledMipMap)
self.mipMap.show()
def download():
mipmaps.save('/path/to/file.png', 'PNG')
def main():
app = QtGui.QApplication(sys.argv)
form = MyApp()
form.show()
app.exec_()
if __name__ == '__main__':
main()
To open/save any documents, there are two steps:
Get the path as a string, for example "/home/Documents/myImage.png". One way to get the path is to ask the user in a dialog.
Qt provides methods to do this, one being getSaveFileName(). From the doc:
This is a convenience static function that will return a file name
selected by the user. The file does not have to exist.
This methods returns a file name: it does not save anything.
Open or save the document, using the path.
To load the image, you used pixmap = QPixmap(imagePath)
To save it, you can use pixmap.save(imagePath) (doc)
Related
I'm using PyQt5.
The goal is to display multiple icons/ Images in a QListWidget and have the data as text next to it.
The data is taken from a specific folder and the paths of each image get converted into icons.
Unfortunately it seems that I have to create an individual Item for each Icon using QtGui.QIcon and then assign the created QIcon to single variable that contains QtWidget.QListWidgetItem() method.
That ofc is quite inefficient. I want to dynamically include or delete parts of the database and have the list adjust accordingly.
If I try to write a for loop that iterates over i in icon_list and try to use the QtWidgets.QListWidgetItem() method on all of them, it returns an error:
TypeError: arguments did not match any overloaded call:
addItem(self, QListWidgetItem): argument 1 has unexpected type 'QIcon'
addItem(self, str): argument 1 has unexpected type 'QIcon'
Any suggestions on how to display a list of images + information more easily in PyQT5?
from PyQt5 import QtWidgets, QtGui
from PyQt5 import QtCore
from PyQt5.QtGui import QPixmap, QImage, QStandardItemModel, QStandardItem
import random
import sys
import os
class MainScreen(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.setupUi(self)
## pictures
path = "/Users/lucasszikszai/Desktop/Coding/Galerie/Datenbank/Julio Rondo/"
self.name_list = os.listdir("/Users/lucasszikszai/Desktop/Coding/Galerie/Datenbank/Julio Rondo")
#self.picture_label.setPixmap(QPixmap(f"/{path}{self.name_list[1]}"))
self.full_paths = [path + i for i in self.name_list]
## convert pictures to icons
icon1 = QtGui.QIcon(path+self.name_list[1])
icon_list = [QtGui.QIcon(icon) for icon in self.full_paths]
# .addItems(list) takes a list of something and displays it
self.inventory.setIconSize(QtCore.QSize(250, 250))
self.inventory.addItems(self.name_list)
item = QtWidgets.QListWidgetItem(icon1, "Test")
#self.inventory.addItems(QtWidgets.QListWidgetItem(icon_list, "Test"))
self.inventory.addItem(item)
## buttons
self.hit_button.clicked.connect(self.generator)
def generator(self):
r_number = random.randint(1, 100)
self.number_display.setText(f"{str(r_number)}")
return r_number
if __name__ == "__main__":
app = QtWidgets.QApplication([])
widget = MainScreen()
widget.show()
app.exec()```
I'm trying to figure out how to use Signal to send custom messages/commands between widgets. I've been up and down all kinds of sources and I still can't figure it out.
The base purpose is that, I want to set a picture in GUI (custom button) that when I click on it, it changes the index number of a stacked widget. But to simplify, I figured click on image, it just prints a message, like 'hi' --> But even better would be if that message could be a predefined string (ala, the index number that I want to connect my image to)
I have so many setups but I'm going to try and write here what I think is my best.
from PySide2.QtCore import *
from PySide2.QtWidgets import *
from PySide2.QtGui import *
import sys
from PIL import Image, ImageQt
def just_go():
app.exit()
app = QtWidgets.QApplication(sys.argv)
window = QtWidgets.QMainWindow()
screen = app.primaryScreen()
size = screen.size()
# <Code that sizes the window based on screensize>
program_window = window.size()
if program_window.width() > 200 and program_window.height() > 100:
s_exit = QtWidgets.QPushButton(text="Quit", parent=window)
s_exit.setGeometry(program_window.width() - 140, program_window.height() - 50, 120, 30)
s_exit.clicked.connect(just_go)
image = ImageQt(Image.open('file'))
clicker = QLabel(window)
clicker.setPixmap(image)
b_buffer = QWidget(window)
foreground = QStackedLayout()
page_0 = QWidget()
page_1 = QWidget()
page_2 = QWidget()
foreground.addWidget(page_0)
foreground.addWidget(page_1)
foreground.addWidget(page_2)
b_buffer.setLayout(foreground)
window.show()
sys.exit(app.exec_())
and then:
def switch_tabs(page):
foreground.setCurrentIndex(page)
Now I'm trying to make my project modular, so the actual file is in multiple python files but how would I make a Signal in one widget that emits to another? And then have a function run whenever that signal is sent?
the problem i had with QGraphicsView it shows images (Pillow generated images) with low quality that i can't read the text on image however i can see details better if i zoomed but on its full size it's not clear and very disappointing.
here is two samples one of the problem and one of wut it should be fixed to.
QGraphicsView scene quality problem
and this
same image opened from windows image viewer with same size:
link for sample: https://imgur.com/a/JINAq4S
the code sample which will cover the issue.
font link: https://gofile.io/d/dXesZv
from PyQt5 import QtWidgets, QtGui, QtCore, QtMultimedia
from PIL import Image, ImageDraw, ImageFont
from PIL.ImageQt import ImageQt
import os
class Main(QtWidgets.QWidget):
def __init__(self, parent=None):
super().__init__(parent)
#the image that would be viewed in QGraphicsView.
_fnt = ImageFont.truetype("ar.ttf" , 100)
_image = Image.new("RGBA", size=(2480, 3508), color="white")
_draw = ImageDraw.Draw(_image)
_draw.text((1000, 200), text="See See", fill="black", font=_fnt)
#QGraphicsView ...
_image.save("sample.png") ; os.startfile("sample.png") # to see what it should look like, like windows image viewer shows it.
self.result = ImageViewer(self, _image)
_layout = QtWidgets.QVBoxLayout()
_layout.addWidget(self.result)
self.setLayout(_layout)
class ImageViewer(QtWidgets.QGraphicsView):
def __init__(self, parent, image):
super(ImageViewer, self).__init__(parent)
self._scene = QtWidgets.QGraphicsScene(self)
qim = ImageQt(image)
self._pixmap = QtGui.QPixmap.fromImage(qim)
self._photo = QtWidgets.QGraphicsPixmapItem(self._pixmap)
self._scene.addItem(self._photo)
self.setScene(self._scene)
self.setBackgroundBrush(QtGui.QBrush(QtGui.QColor(230, 230, 230)))
def resizeEvent(self, event):
self.fitInView(self._photo, QtCore.Qt.KeepAspectRatio)
super().resizeEvent(event)
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
main = Main()
main.setWindowState(QtCore.Qt.WindowMaximized)
main.show()
app.exec_()
eventually I came up to kinda an answer to my question:
the issue was:
QGraphicsView's performance with high resolution images is poor (can't read small details in image) as antialiasing algorithm doesn't work well with very small details.
what I tried, helped but never solved:
I used .setTransformationMode(QtCore.Qt.SmoothTransformation) and .setRenderHints(QtGui.QPainter.Antialiasing | QtGui.QPainter.HighQualityAntialiasing) which helped.
what I gave away to solve it:
I resized the high resolution image to a smaller resolution that can be viewed a good quality with the ability to read small details like small text.
how i resized the image:-
the image used in the scene is a pillow object so i used the method .resize((int(image.size[0]/3.5), int(image.size[1]/3.5)), Image.ANTIALIAS), notice 1/3.5 ratio is optional.
In PyQt4, is there a way to suspend resize of a window until a function is completed?
My problem is that I have created a window with a text edit that might contain large amounts of text. Since I switched to working with a grid layout, the text edit gets resized as well, and when there is a lot of text, the application hangs. I tried overriding resizeEvent to clear text edit text at resize but the application still hangs, since it is clearing the text only AFTER resizing.
Other solutions are welcomed as well.
The python code (and a link to the .ui file):
import sys
from PyQt4 import QtGui, uic, QtCore
from PyQt4.QtGui import QDesktopWidget
qtCreatorMainWindowFile = "mainwindow.ui"
Ui_MainWindow, QtBaseClass = uic.loadUiType(qtCreatorMainWindowFile)
class MainWindow(QtBaseClass, Ui_MainWindow):
def __init__(self):
QtBaseClass.__init__(self)
self.setupUi(self)
# Set window size to 4/5 of the screen dimensions
sg = QDesktopWidget().screenGeometry()
self.resize(sg.width()*4/5, sg.height()*4/5)
self.clearTextBrowserButton.clicked.connect(self.ClearTextBrowsers)
#staticmethod
def WriteToTextBrowser(string, text_browser):
cursor = text_browser.textCursor()
cursor.movePosition(QtGui.QTextCursor.End)
cursor.insertText(string)
text_browser.setTextCursor(cursor)
text_browser.ensureCursorVisible()
def ClearTextBrowsers(self):
self.textBrowser.clear()
# def resizeEvent(self,event):
# print "resize"
# self.ClearTextBrowsers()
app = QtGui.QApplication(sys.argv)
window = MainWindow()
window.show()
for i in range(1,100000):
window.WriteToTextBrowser("TESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTEST\r\n",window.textBrowser)
sys.exit(app.exec_())
The ui. file:
https://www.dropbox.com/s/y3hxp6mjhfpv2hy/mainwindow.ui?dl=0
I found a workaround that seems to work so far. I added an event filter that catches "Move" or "WindowStateChange" QEvents. These seem to happen before the actual resize (the prior works for clicking and stretching and the latter for maximizing/minimizing). The downside is that simply moving the window clears the text edit, but it is a price I'm willing to pay.
The added code (inside MainWindow):
self.installEventFilter(self)
def eventFilter(self, source, event):
if (event.type() == QtCore.QEvent.Move or event.type() == QtCore.QEvent.WindowStateChange):
self.file.write(self.textBrowser.toPlainText())
self.ClearTextBrowsers()
return QtBaseClass.eventFilter(self, source, event)
I have data coming from two sources , one from XML file save paths , second one from QFileSystemModel which I want to work if the user couldn't see the path then in QLineEdit the user should be able to browse path !! the first letter obviously "/" or single letter for windows .
just for the example I have simple replaced the XMLData from file to defaultList of paths.
The below code works for a while but I get segmentation fault.
from PyQt4.Qt import Qt, QObject,QLineEdit
from PyQt4.QtCore import pyqtSlot,SIGNAL,SLOT
from PyQt4 import QtGui, QtCore
import sys
class DirLineEdit(QLineEdit, QtCore.QObject):
"""docstring for DirLineEdit"""
def __init__(self):
super(DirLineEdit, self).__init__()
self.defaultList = ['~/Development/python/searchMethod', '~/Development/Nuke_python',
'~/Development/python/openexr', '~/Development/python/cpp2python',
'~/Development/python/using_argparse', '~Development/python/listFilter']
self.textChanged.connect(self.switchCompleter)
self._pathsList()
def focusInEvent(self, event):
QtGui.QLineEdit.focusInEvent(self, event)
self.completer().complete()
def switchCompleter(self):
if len(self.text()) >= 1:
self.__dirCompleter()
if len(self.text()) == 0:
self.__pathsList()
def __dirCompleter(self):
dirModel = QtGui.QFileSystemModel()
dirModel.setRootPath(QtCore.QDir.currentPath())
dirModel.setFilter(QtCore.QDir.AllDirs | QtCore.QDir.NoDotAndDotDot | QtCore.QDir.Files)
dirModel.setNameFilterDisables(0)
completer = QtGui.QCompleter(dirModel, self)
completer.setModel(dirModel)
completer.setCaseSensitivity(QtCore.Qt.CaseInsensitive)
self.setCompleter(completer)
def _pathsList(self):
completerList = QtCore.QStringList()
for i in self.defaultList:
completerList.append(QtCore.QString(i))
lineEditCompleter = QtGui.QCompleter(completerList)
lineEditCompleter.setCompletionMode(QtGui.QCompleter.UnfilteredPopupCompletion)
self.setCompleter(lineEditCompleter)
app = QtGui.QApplication(sys.argv)
smObj = DirLineEdit()
smObj.show()
app.exec_()
the above code gives Segmentation fault: 11
Is there a better way I can use both completer with one ?