Python PyQt4 how to open image using QFileDialog - python

I have to write a program with an option to open an image from a file. I have to use QFileDialog and display image in QLabel, using QPixmap. I am able to use them individually but I didn't manage to combine them.
I think I need to take my image name from dlg.selectedFiles but I don't know how to choose the moment when there is useful data in it. Do I need to make a loop in my main program, and constantly check if there is image to open? Can I send a signal to my label using openAction.triggered.connect(...)?
from PyQt4 import QtGui
import sys
class MainWindow(QtGui.QMainWindow):
def __init__(self, parent = None):
super(MainWindow, self).__init__(parent)
menubar = self.menuBar()
fileMenu = menubar.addMenu('File')
dlg = QtGui.QFileDialog(self)
openAction = QtGui.QAction('Open', self)
openAction.triggered.connect(dlg.open)
fileMenu.addAction(openAction)
#label = QtGui.QLabel(self)
#pixmap = QtGui.QPixmap('')
#label.setPixmap(pixmap)
def main():
app = QtGui.QApplication(sys.argv)
win = MainWindow()
win.show()
app.exec_()
if __name__ == '__main__':
sys.exit(main())

You need to make your own slot and connect it to the openAction signal.
In your __init__ function do:
openAction.triggered.connect(self.openSlot)
In your class MainWindow define the following function:
def openSlot(self):
# This function is called when the user clicks File->Open.
filename = QtGui.QFileDialog.getOpenFileName()
print(filename)
# Do your pixmap stuff here.

Related

MouseClick Event on PyQt Folder Tree

I have coded out a small application using PyQt5. The application gives a tree view of all folders in the computer plus a lineEditd where the user can type things:
import sys
from PyQt5.QtWidgets import (
QMainWindow, QApplication,
QHBoxLayout,QWidget,
QVBoxLayout,QFileSystemModel, QTreeView, QLineEdit
)
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
layout = QHBoxLayout()
application = App()
layout.addWidget(application)
widget = QWidget()
widget.setLayout(layout)
self.setCentralWidget(widget)
class App(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.model = QFileSystemModel()
self.model.setNameFilters([''])
self.model.setNameFilterDisables(0)
self.model.setRootPath('')
self.tree = QTreeView()
self.tree.setModel(self.model)
self.tree.setAnimated(False)
self.tree.setSortingEnabled(True)
layout = QVBoxLayout()
layout.addWidget(self.tree)
self.input = QLineEdit()
layout.addWidget(self.input)
self.setLayout(layout)
self.show()
app = QApplication(sys.argv)
w = MainWindow()
w.show()
app.exec()
My next goal is to make my application able to detect mouse click on the tree diagram. More precisely, in an event of a mouse click on any folder in the tree, I want to know the directory of the folder which the user clicks (so that I can, for instance, update the LineEdit by filling it with the directory)
To achieve such a goal, the first thing I need to do is to make mouse click in the tree an event. If I add a method like:
def mouseMoveEvent(self, e):
#some code
It will not give me an event reflecting the fact that the mouse click happens in the tree. I am therefore stuck on even making mouse click in tree an event, nor to mention reading the directory .
Edit:
By writing
self.tree.clicked
I am able to detect any click in the tree. However, I still do not know how to get the directory.
If you want to get the directory using the view's clicked signal then you should use the model:
self.tree.clicked.connect(self.handle_clicked)
def handle_clicked(self, index):
filename = self.model.fileName(index)
path = self.model.filePath(index)
fileinfo = self.model.fileInfo(index)
print(filename, path, fileinfo)

How to make an image selectable using pixmap and Qlabel?

I am trying to show multiple images using Pyqt5. It would be nice to make the image selectable within the GUI so that the users can select and copy that image right away easily.
By "selectable", I meant the user can right click the image and then copy it and then potentially paste it to somewhere else outside of the GUI. Just like a normal image saved in a Word. User can select/copy an image in Word and then paste it to somewhere else.
I know for Text in Qlabel this can easily achieved by using self.my_label.setTextInteractionFlags(QtCore.Qt.TextSelectableByMouse). However, it seems for images there is no such method handling it. Is there any way I can work it out for images?
import sys
import PyQt5
from PyQt5.QtWidgets import (
QLabel,
QVBoxLayout,
QWidget
)
from PyQt5 import QtCore
from PyQt5.QtGui import QPixmap
from PyQt5.QtCore import QSize
class Display_Window(QWidget):
def __init__(self):
super().__init__()
self.setMinimumSize(QSize(980,700))
self.layout = QVBoxLayout(self)
self.label1 = QLabel(self)
self.pixmap = QPixmap(path_to_my_image)
self.pixmap = self.pixmap.scaled(900, 900, QtCore.Qt.KeepAspectRatio)
self.label1.setPixmap(self.pixmap)
self.label1.resize(self.pixmap.width(), self.pixmap.height())
# Run if Script
if __name__ == "__main__":
app = PyQt5.QtWidgets.QApplication(sys.argv)
MainWindow = Display_Window() # Initialize GUI
MainWindow.show() # Show Window
app.exec_()
You can subclass the label and create a menu whenever it has a valid pixmap, then use the system clipboard to copy it.
class CopiableLabel(QLabel):
def contextMenuEvent(self, event):
pixmap = self.pixmap()
if not pixmap.isNull():
menu = QMenu()
copyAction = menu.addAction('Copy image to clipboard')
if menu.exec_(event.globalPos()) == copyAction:
QApplication.clipboard().setPixmap(pixmap)
return
super().contextMenuEvent(event)
class Display_Window(QWidget):
def __init__(self):
super().__init__()
self.layout = QVBoxLayout(self)
self.label1 = CopiableLabel(self)
self.layout.addWidget(self.label1)
self.pixmap = QPixmap(path_to_my_image)
self.pixmap = self.pixmap.scaled(900, 900, Qt.KeepAspectRatio)
self.label1.setPixmap(self.pixmap)
Note that setting a pixmap on a QLabel automatically resizes it (unless it has the scaledContents property set to True.
You also should add the label to the layout, as I did in the above modifications.

PySide: Unable to use method show() outside of __init__ for proper window display

I've been researching recently Qt development with PySide, however I cannot go through one thing. I want to load ui in not directly in init but in own init_ui method (just for science purposes). But no matter what I will do I cannot make it to work when calling show() from the __main__ function. Like in example here.
Should work, but it's not:
mw = MainWindow()
# this displays empty window
mw.show()
However proper window is displayed when calling directly from __init__:
def __init__(self):
super(MainWindow, self).__init__()
# this shows proper
self.show()
self.init_ui()
self.load_widgets()
Here is whole code:
from PySide import QtCore,QtGui
from PySide import QtUiTools
import os, sys
def load_ui(file_name, where=None):
"""
Loads a .UI file into the corresponding Qt Python object
:param file_name: UI file path
:param where: Use this parameter to load the UI into an existing class (i.e. to override methods)
:return: loaded UI
"""
# Create a QtLoader
loader = QtUiTools.QUiLoader()
# Open the UI file
ui_file = QtCore.QFile(file_name)
ui_file.open(QtCore.QFile.ReadOnly)
# Load the contents of the file
ui = loader.load(ui_file, where)
# Close the file
ui_file.close()
return ui
class MainWindow(QtGui.QMainWindow):
def __init__(self):
super(MainWindow, self).__init__()
# this shows proper
self.show()
self.init_ui()
self.load_widgets()
def init_ui(self):
"""
init ui
:return:
"""
ui_file_path = os.path.join(os.path.realpath(os.path.dirname(__file__)), 'window.ui')
print ui_file_path
# it returns ui but I have no idea what to do with it
# main_widget = load_ui(ui_file_path, self)
load_ui(ui_file_path, self)
# return main_widget
def load_widgets(self):
"""
here configuring rest of widgets
:return:
"""
export_path_button = self.findChild(QtGui.QPushButton, 'export_path_button')
export_path_button.clicked.connect(self.on_export_path_button_clicked)
def on_export_path_button_clicked(self):
"""
test if works
:return:
"""
print "clicked!"
filename = QtGui.QFileDialog.getSaveFileName(parent=self, caption='Select output file', dir='.')
if filename:
print filename
def main():
app = QtGui.QApplication(sys.argv)
mw = MainWindow()
# this displays empty window
mw.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
Because you must call show method in main() but not in __init__() method. Sorry for my english

How to open a window with a click of a button from another window using PyQt?

I'm trying to make an application but I keep getting punched by the "simple" things like this one, how do I open a new window though a button click? I tried using new_lib_btn.clicked.connect(newlib), newlib is the file that contains my second window and new_lib_btn is the button that should open the window, it's in my main window as you can see down here:
mainwindow.py
from PyQt4 import QtCore, QtGui
import newlib
import sys
# Main Window
class Window (QtGui.QMainWindow):
def __init__(self):
super(Window, self).__init__()
centralwidget = QtGui.QWidget(self)
self.mainLayout = QtGui.QVBoxLayout(centralwidget)
self.mainLayout.setAlignment(QtCore.Qt.AlignCenter)
self.setCentralWidget(centralwidget)
self.resize(800, 600)
self.setWindowTitle("Virtual Library")
self.setStyleSheet("Window {border-image: url(lib.jpg);}")
# ExitOption
menu_action1 = QtGui.QAction("Exit", self)
menu_action1.setShortcut("Ctrl+Q")
menu_action1.setStatusTip('Exit The App')
menu_action1.triggered.connect(self.close_application)
self.statusBar()
# MenuBar
main_menu = self.menuBar()
file_menu = main_menu.addMenu('Options')
file_menu.addAction(menu_action1)
self.home()
def home(self):
# NewLibrary btn
new_lib_btn = QtGui.QPushButton("New Library", self)
new_lib_btn.setGeometry(QtCore.QRect(310, 180, 141, 41))
new_lib_btn.setStyleSheet("color: black;")
# AccessLibrary btn
access_lib_btn = QtGui.QPushButton("Access Library", self)
access_lib_btn.setGeometry(QtCore.QRect(310, 250, 141, 41))
access_lib_btn.setStyleSheet("color: black;")
# FindNewBooks btn
find_nbooks = QtGui.QPushButton("Find New Books*", self)
find_nbooks.setGeometry(QtCore.QRect(310, 320, 141, 41))
find_nbooks.setStyleSheet("color: black;")
self.mainLayout.addWidget(new_lib_btn)
self.mainLayout.addWidget(access_lib_btn)
self.mainLayout.addWidget(find_nbooks_btn)
self.show()
def close_application(self):
choice = QtGui.QMessageBox.question(self, 'Exit',
"Close the application?",
QtGui.QMessageBox.Yes | QtGui.QMessageBox.No)
if choice == QtGui.QMessageBox.Yes:
sys.exit()
else:
pass
def run():
app = QtGui.QApplication(sys.argv)
GUI = Window()
sys.exit(app.exec_())
run()
And here's my second window, the one I want to open with the new_lib_btn
newlib.py
class NewLibrary (QtGui.QMainWindow):
def __init__(self):
super(NewLibrary, self).__init__()
self.resize(800,600)
self.setWindowTitle("New Library")
self.setStyleSheet("NewLibrary {border-image: url(wood.jpg);}")
# File Options
file_action1 = QtGui.QAction("New Library", self)
file_action1.setShortcut("Ctrl+N")
file_action1.setStatusTip("Creates a new library")
file_action2 = QtGui.QAction("Exit this!", self)
file_action2.setShortcut("Ctrl+Q")
file_action2.setStatusTip("Closes The App")
file_action2.triggered.connect(self.close_application)
#File Menu
main_menu = self.menuBar()
file_menu = main_menu.addMenu("File")
file_menu.addAction(file_action1)
file_menu.addAction(file_action2)
self.newLib()
self.newLib()
def newLib(self):
centralwidget = QtGui.QWidget(self)
self.mainLayout = QtGui.QVBoxLayout(centralwidget)
self.mainLayout.setAlignment(QtCore.Qt.AlignCenter)
#some useful buttons in the future
self.setCentralWidget(centralwidget)
self.show()
def close_application(self):
choice = QtGui.QMessageBox.question(self, 'Exit',
"Close the application?",
QtGui.QMessageBox.Yes | QtGui.QMessageBox.No)
if choice == QtGui.QMessageBox.Yes:
sys.exit()
else:
pass
def runNewLib():
app = QtGui.QApplication(sys.argv)
gui = NewLibrary()
sys.exit(app.exec_())
runNewLib()
I searched a lot about this but I couldn't understand the few ones that were somewhat close to my situation, so I'm asking for help, It seems so simple but I'm not getting it :/, what should I do to open the second window by clicking new_lib_btn? pls help.
I think there are several issues with the code that you've posted. First, there are two calls to self.newLib() in the NewLibrary constructor. Second, you probably want to put that call to runNewLib() at the bottom of newlib.py behind an if __name__... block, like so:
if __name__ == '__main__':
runNewLib()
Otherwise, every time you try to import newlib.py, it will attempt to run NewLibrary as a separate application.
Getting to the question you asked, I don't think you actually want to call self.show() in either Window.home() or NewLibrary.newLib(). A more typical pattern would be to create an instance of either Window or NewLibrary and then call show() on that instance. So, in your Window class, you'd add a function to create an instance of NewLibrary and then call show on it, like this
def create_new_library_window(self):
self.new_lib = newlib.NewLibrary()
self.new_lib.show()
Note that, as ekhumoro points out, you have to keep a reference to new_lib around, otherwise it will get garbage collected when the function exits. Then in NewLibrary.home() after you've created the new_lib_btn connect it to this new function:
new_lib_btn.clicked.connect(self.create_new_library_window)
Working example
This example creates a main window with one big button that, when clicked will open a second window. It uses two classes that inherit from QMainWindow, as in your question. First, in main.py:
from PyQt4 import QtGui
from new_window import NewWindow
class Window(QtGui.QMainWindow):
def __init__(self):
super(Window, self).__init__()
self._new_window = None
self._button = QtGui.QPushButton('New Window', self)
self._button.clicked.connect(self.create_new_window)
self.setCentralWidget(self._button)
def create_new_window(self):
self._new_window = NewWindow()
self._new_window.show()
if __name__ == '__main__':
app = QtGui.QApplication([])
gui = Window()
gui.show()
app.exec_()
The __init__ function creates a button and connects it to the create_new_window function. When the button is clicked, create_new_window will be called. Inside of create_new_window, we create an instance of NewWindow and assign it to a class member to maintain a reference to the window and prevent it from being garbage collected. We then call show on this new window to display it.
At the bottom, we use the usual if __name__ == '__main__': pattern to control whether this file runs the application or not. If this file is executed from the command line (like python main.py) __name__ == '__main__' evaluates to true and the GUI application will be started. This has the advantage of allowing the file to serve a dual purpose: it can be imported as a standard python package, or executed as an application, all using the same file.
Then in new_window.py:
from PyQt4 import QtGui
class NewWindow(QtGui.QMainWindow):
def __init__(self):
super(NewWindow, self).__init__()
self._new_window = None
self._label = QtGui.QLabel('Hello, is it me you\'re looking for?')
self.setCentralWidget(self._label)
if __name__ == '__main__':
app = QtGui.QApplication([])
gui = NewWindow()
gui.show()
app.exec_()
This file defines a second QMainWindow that uses a label as its central widget. It also uses the __name__ == '__main__' pattern; this file can also be executed as a standalone application or imported as in main.py above.

How to make one window to block another without using .setModal(True)

If main window right-clicked a QInputDialog shows up. I want QInputDialog to block main window while it is open. How to achieve this?
from PyQt4 import QtCore, QtGui
app = QtGui.QApplication([])
class AppWindow(QtGui.QMainWindow):
def __init__(self):
super(AppWindow, self).__init__()
mainWidget=QtGui.QWidget()
self.setCentralWidget(mainWidget)
mainLayout = QtGui.QVBoxLayout()
mainWidget.setLayout(mainLayout)
frame=QtGui.QFrame()
frame.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
frame.connect(frame, QtCore.SIGNAL("customContextMenuRequested(QPoint)" ), self.up)
mainLayout.addWidget(frame)
self.modal=QtGui.QInputDialog()
def up(self, QPos):
self.modal.move(QtGui.QCursor.pos())
self.modal.show()
self.modal.raise_()
window=AppWindow()
window.show()
sys.exit(app.exec_())
OK, This solution can be solve by use method QWidget.setWindowModality (self, Qt.WindowModality windowModality) . A modal window is one that blocks input to other windows. Note that windows that are children of a modal window are not blocked.
Add this line in your initial method;
self.modal.setWindowModality(QtCore.Qt.ApplicationModal)
Completed code is;
import sys
from PyQt4 import QtCore, QtGui
class AppWindow (QtGui.QMainWindow):
def __init__ (self):
super(AppWindow, self).__init__()
mainWidget = QtGui.QWidget(self)
self.setCentralWidget(mainWidget)
mainLayout = QtGui.QVBoxLayout()
mainWidget.setLayout(mainLayout)
frame = QtGui.QFrame()
frame.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
frame.connect(frame, QtCore.SIGNAL("customContextMenuRequested(QPoint)" ), self.up)
mainLayout.addWidget(frame)
self.modal = QtGui.QInputDialog(self)
self.modal.setWindowModality(QtCore.Qt.ApplicationModal)
def up (self, QPos):
self.modal.move(QtGui.QCursor.pos())
self.modal.show()
self.modal.raise_()
app = QtGui.QApplication([])
window = AppWindow()
window.show()
sys.exit(app.exec_())
Reference method : http://pyqt.sourceforge.net/Docs/PyQt4/qwidget.html#setWindowModality
Reference enum : http://pyqt.sourceforge.net/Docs/PyQt4/qt.html#WindowModality-enum
Regards,
In a nut shell, this is the basic approach. I have created a second window (a Frame), containing a table widget, and the name of my class is TableWindow. Import that in your main window file. On a button click, I call the below function.
def call_table_window(self):
self.frame = QtGui.QFrame()
self.window_table = TableWindow()
self.window_table.setupUi(self.frame)
#This stops the user to switch to the main window. He has to close
#the 2nd window first.
self.frame.setWindowModality(QtCore.Qt.ApplicationModal)
self.frame.show()
Especially when working with PyQt5, you can set inside the __init__
self.setWindowModality(QtCore.Qt.ApplicationModal)

Categories