PyQt QFileDialog getOpenFileName not working from command line (windows) - windows

I'm trying to make a gui (Qt Designer) to import an excel file and display the data in the gui.
The script works fine when I run it from within my IDE (Spyder), but if I run it from the command window or by opening the python file from windows explorer, the import function does not work. (The gui starts up fine but when the import button is pressed and the file is selected, nothing happens and no error is produced. When running from Spyder, the data is imported and displayed in the gui as expected).
If I pre-select the file location (commented out in the code below), then the script works fine from the command line or by clicking from explorer.
Thanks for any help!
Python 2.7 (Anaconda), Windows 10, PyQt4
import sys
from PyQt4 import QtGui
from excel_import_gui import Ui_MainWindow
import xlrd
class Main(QtGui.QMainWindow):
def __init__(self):
QtGui.QMainWindow.__init__(self)
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
self.setupSignals()
def set_import_data(self,data_to_import,table_to_change):
for row in range(len(data_to_import)):
for col in range(len(data_to_import[0])):
table_to_change.setRowCount(len(data_to_import))
table_to_change.setColumnCount(len(data_to_import[0]))
item = data_to_import[row][col]
table_to_change.setItem(row,col,QtGui.QTableWidgetItem(str(item)))
def setupSignals(self):
self.ui.importData_btn.clicked.connect(self.select_file)
def select_file(self):
excel_file = QtGui.QFileDialog.getOpenFileName(self,
"Select Excel file to import","","Excel (*.xls *.xlsx)")
# excel_file = "C:/Users/Ben/Work/Python tests/Qt GUIs/Excel_import_GUI/fish_test.xlsx"
if excel_file:
open_excel_file = xlrd.open_workbook(excel_file)
self.start_import_data(open_excel_file)
def start_import_data(self, workbook):
#import data from excel file
workbook_data = []
for sheetNum in range (workbook.nsheets):
worksheet = workbook.sheet_by_index(sheetNum)
workbook_data.append([[worksheet.cell_value(row,col) for col in range (worksheet.ncols)] for row in range(worksheet.nrows)])
# Set each worksheet of workbook_data to each tab in GUI widget
self.set_import_data(workbook_data[0],self.ui.fish_table)
self.set_import_data(workbook_data[1],self.ui.boats_table)
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
window = Main()
window.show()
sys.exit(app.exec_())

Well I found a solution myself by converting the excel_file variable to a string.
excel_file = str(QtGui.QFileDialog.getOpenFileName(self, "Select Excel file to import","","Excel (*.xls *.xlsx)"))

Related

Windows "Command Prompt" inside tkinter frame

How to run command prompt inside tkinter frame? I know how to do it with "pygame", but those methods doesn't work - command prompt just runs in another window.
I tried to do it like this:
import tkinter as tk
import os
import subprocess
root = tk.Tk()
root.geometry("640x480")
frame = tk.Frame(root)
frame.pack(fill="both", expand=True)
child_env = dict(os.environ)
child_env["SDL_WINDOWID"] = str(frame.winfo_id())
child_env["SDL_VIDEODRIVER"] = "windib"
p = subprocess.Popen(["cmd.exe"], env=child_env)
root.mainloop()
But, as i said, it doesn't work.
This does not use "Command Prompt" as in the program included with Windows, but ConEmu has an -insidewnd parameter which is meant for allowing it to be embedded in third-party applications.
import sys,pathlib,subprocess
import tkinter as tk
import tkinter.ttk as ttk
# assuming a common location for the portable conemu installation:
conemu_exe = pathlib.Path.home()/"Documents"/"ConEmu"/"ConEmu64.exe"
class app(tk.Tk):
def __init__(self):
super().__init__()
self.console_frame = ttk.Frame(self,height=480,width=640)
self.console_frame.pack(fill="both",expand=True)
hwnd = hex(self.console_frame.winfo_id())
p = subprocess.Popen(
[str(conemu_exe), "-insidewnd", hwnd],
stdin=subprocess.PIPE,
stdout=subprocess.PIPE)
app().mainloop()
from tkinter import Tk, Text
import subprocess
def execute(code):
command = cmd.get('1.0', 'end').split('\n')[-2]
if command == 'exit':
exit()
cmd.insert('end', f'\n{subprocess.getoutput(command)}')
main = Tk()
cmd = Text(main)
cmd.pack()
cmd.bind('<Return>', execute)
main.mainloop()

Terminating an exe built from a GUI in python from Background Processes

I created a simple GUI in python 3.4 using tkinter 8.5. I used cx_freeze to build an exe from this GUI. Now when I run this exe, sometimes I notice that the program still shows under 'Background Processes' in Task Manager even after I terminate it using a Quit button or using the close button in the window.
The GUI works like this: You select a file type from a drop down list, read the file using a command button and save it as a separate file. Now this problem happens only if I close the GUI after using it. If I simply open the GUI and close it using the Quit button or close button, it does not stay as a background process.
Is it normal for it to behave like this? If not what can I do to terminate it properly?
The simplified code for the GUI is given below. The function 'fileselect' calls functions from the module 'dataselect'. If needed, I will provide the code for the 'dataselect' module also.
from dataselect import *
from openpyxl import Workbook
from tkinter import *
from tkinter import ttk, filedialog
root = Tk()
root.title("Select Data File")
# Actual File Selection based on Combobox Selection
def fileselect():
file_type = filetype.get()
if file_type == ".txt":
text = selecttxt()
textfile = filedialog.asksaveasfile(mode='w', defaultextension=".txt")
for line in text:
for number in line:
textfile.write(str(number)+" ")
textfile.write('\n')
elif file_type == ".xlsx":
excel = selectxlsx()
excelfile = filedialog.asksaveasfile(mode='w', defaultextension=".xlsx")
excelfilename = excelfile.name
excelbook = Workbook()
excelsheet = excelbook.active
rows = 0
for excel_row in excel:
cols = 0
for excel_cell in excel_row:
excelsheet.cell(row=rows, column=cols).value = excel[rows][cols]
cols += 1
rows += 1
excelbook.save(excelfilename)
def quit():
global root
root.destroy()
# Select the File Type to be opened (.txt or .xlsx for now)
ttk.Label(root, text="Please select the file type").grid(column=2, row=1)
filetype = StringVar()
sel_type = ttk.Combobox(root,values=('.txt','.xlsx'),textvariable=filetype)
sel_type.grid(column=2,row=2,sticky=E)
# Command Button for Opening File
cb_open = ttk.Button(root, text="Select File", command=fileselect)
cb_open.grid(column=2, row=3)
# Command Button for Quitting GUI
cb_quit = ttk.Button(root, text="Quit", command=quit)
cb_quit.grid(column=1, row=3)
root.mainloop()
There are two things you need to change:
1) Add sys.exit() to your quit method
def quit():
root.quit
root.destroy
sys.exit()
2) Add protocol to your root
root.protocol("WM_DELETE_WINDOW", quit)
Finally, don't forget to import sys.

cx_freeze issue with relative path on mac

I'm having issues with cx_freeze relative path logic on mac. I'm using python 3.3 and pyqt5 and building an app portable windows - mac.
The following simple script just loads an image into a QLabel as a QPixmap.
The code works fine both on windows and mac when launched from console, builds both on windows and mac.
The exe works on windows without any problem.
The app ( MacOSX ) does not load the image, same for the dmg.
I have a feeling it has something to do with relative path setting. The reason for this belief is the following:
- if I try to load the .app the image will not appear
- if I copy-paste the testimage.jpeg in the same folder where the .app is it will load the image.
I did try include_files in the setup with no results.
Can anyone help?
Here are the scripts:
First the file image_insert_test.py:
import sys
from PyQt5.QtWidgets import (QApplication, QDialog,
QErrorMessage, QLabel, QWidget, QVBoxLayout )
from PyQt5.QtCore import pyqtSlot, QDir, Qt
from PyQt5 import QtGui
class Window(QDialog):
def __init__(self, parent=None):
super(Window, self).__init__(parent)
self.fill_box2 = QLabel()
pixmap = QtGui.QPixmap('testimage.jpeg')
self.fill_box2.setPixmap(pixmap.scaled(100,100,Qt.KeepAspectRatio))
# set the layout
layout = QVBoxLayout()
layout.addWidget(self.fill_box2)
self.setLayout(layout)
if __name__ == '__main__':
app = QApplication(sys.argv)
main = Window()
main.setWindowTitle('test gui')
main.show()
sys.exit(app.exec_())
the file setup.py:
import sys
from cx_Freeze import setup, Executable
base = None
if sys.platform == 'win32':
base = 'Win32GUI'
options = {
'build_exe': {
"includes": ["matplotlib.backends.backend_macosx"] ,
"include_files" : ["testimage.jpeg"]
}
}
executables = [
Executable('image_insert_test.py', base=base)
]
setup(name='image_insert_test',
version='0.1',
description='Sample image_insert_test script',
options=options,
executables=executables
)
and this is the log of the cx_freeze bdist_mac http://pastebin.com/77uU4Exr
a workaround is the following:
instead of
pixmap = QtGui.QPixmap('testimage.jpeg')
place:
pixmap = QtGui.QPixmap(os.path.join(os.getcwd(),'image_insert_test-0.1.app/Contents/MacOS','testimage.jpeg')
this fishes the image path from the .app package but there has to be a more elegant way to do it.

PyQt getOpenFileName default directory

I'm using Qt.Gui.QFileDialog.getOpenFileName method to open a file. If I set the default file directory to "/Users/me/Documents/data/2013/today/" the dialog box opens to "/Users/me/Documents/data/2013/" with the "today" folder selected. How do I get the the correct default folder to be opened in the window?
fname = QtGui.QFileDialog.getOpenFileName(self, 'Open file', "/Users/me/Documents/data/2012/20121102/images/",'*.npy')
Opens a dialog box in /Users/me/Documents/data/2012/20121102. I want the window to open in /Users/me/Documents/data/2012/20121102/images/
The most probable reason is that the file doesn't exist at the time you are requesting it be opened. For opening folders use QtGui.QFileDialog.getExistingDirectory:
#!/usr/bin/env python
#-*- coding:utf-8 -*-
from PyQt4 import QtGui, QtCore
class MyWindow(QtGui.QWidget):
def __init__(self, parent=None):
super(MyWindow, self).__init__(parent)
self.pushButtonOpen = QtGui.QPushButton(self)
self.pushButtonOpen.setText("Open Folder")
self.pushButtonOpen.clicked.connect(self.on_pushButtonOpen_clicked)
self.layoutHorizontal = QtGui.QHBoxLayout(self)
self.layoutHorizontal.addWidget(self.pushButtonOpen)
#QtCore.pyqtSlot()
def on_pushButtonOpen_clicked(self):
folderName = QtGui.QFileDialog.getExistingDirectory(
self, "Open Directory",
"/path/to/folder",
QtGui.QFileDialog.ShowDirsOnly | QtGui.QFileDialog.DontResolveSymlinks,
)
if __name__ == "__main__":
import sys
app = QtGui.QApplication(sys.argv)
app.setApplicationName('MyWindow')
main = MyWindow()
main.show()
sys.exit(app.exec_())
For someone's information (even though 8 years passed)
You could pass the directory argument to getOpenFileName for the default folder in PyQt5.

Popup window on button click

I want to create a code which will display a window with a button, which clicked will create another window with some fields (like QLabel, QLineEdit, QSpinBox, etc.). However, I don't know how to create that popup window...
Here is my code:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys # Needed for PySide
from PySide.QtCore import *
from PySide.QtGui import *
class Form(QDialog):
def __init__(self, parent=None):
super(Form, self).__init__(parent)
# Create widgets
self.label1 = QLabel("Label1")
self.button_open = QPushButton("Open popup")
self.button = QPushButton("Go!")
self.qbtn = QPushButton('Quit')
# Create layout and add widgets
layout = QVBoxLayout()
layout.addWidget(self.label1)
layout.addWidget(self.button_open)
# Buttons layout
hbox_buttons = QHBoxLayout()
hbox_buttons.addStretch(1)
hbox_buttons.addWidget(self.button)
hbox_buttons.addWidget(self.qbtn)
# Main layout
layout.addStretch(1)
layout.addWidget(self.button_open)
layout.addLayout(hbox_buttons)
self.setLayout(layout)
# Add buttons slots
self.button_open.clicked.connect(self.popup)
self.button.clicked.connect(self.function_runner)
self.qbtn.clicked.connect(QCoreApplication.instance().quit)
def popup (self, parent=__init__):
new_win = # I wonder what should be here
if __name__ == '__main__':
# Create the Qt Application
app = QApplication(sys.argv)
# Create and show the form
form = Form()
form.show()
# Run the main Qt loop
sys.exit(app.exec_())
I don't know if this is the best way, but the one I could figure out over the night... I hope it will help someone who got stuck with a similar problem.
So, I (simply) created a separate code for that second window and called it with
from subprocess import call
call("./my_2nd_window_code.py")

Resources