Porting PyQt4 QWorkspace to PyQt5 QMdiArea -- subWindowList method - pyqt

I've run into a snag porting a program example from "Rapid GUI Programming with Python and Qt" from PyQt4 to PyQt5. The sample program demonstrates an MDI application from which multiple text edit windows can be run within the main window.
I used python 3.4.4 and PyQt 4.8.7 for the PyQt4 version. I used python 3.4.4 and PyQt 5.5.1 for the PyQt5 version.
I started by changing all old-style signal definitions to new style signals in the original PyQt4 program. New style signals were implemented in PyQt 4.5 so I was able to run the original program with these changes. The application ran successfully after updating all old-style signals to new-style signals.
The original program uses the PyQt4.QtGui.QWidget.QWorkspace class to implement the MDI workspace. QWorkspace was replaced by the PyQt5.QtWidgets.QMdiArea class in PyQt4.3. My problem surfaced in trying to modify the original code to work with QMdiArea.
Each text document is presented and edited using an instance of a custom TextEdit widget, a subclass of QTextEdit.
Minimal PyQt5 version of MDI application -- texteditor.py
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
class TextEdit(QTextEdit):
NextId = 1
def __init__(self, filename="", parent=None):
print("TextEdit __init__")
super(TextEdit, self).__init__(parent)
self.setAttribute(Qt.WA_DeleteOnClose)
self.filename = filename
if not self.filename:
self.filename = "Unnamed-{}.txt".format(TextEdit.NextId)
TextEdit.NextId += 1
self.document().setModified(False)
self.setWindowTitle(QFileInfo(self.filename).fileName())
def load(self):
print("load - TextEdit")
exception = None
fh = None
try:
fh = QFile(self.filename)
if not fh.open(QIODevice.ReadOnly):
raise IOError(fh.errorString())
stream = QTextStream(fh)
stream.setCodec("UTF-8")
self.setPlainText(stream.readAll())
self.document().setModified(False)
except EnvironmentError as e:
exception = e
finally:
if fh is not None:
fh.close()
if exception is not None:
raise exception
import sys
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
__version__ = "1.0.0"
class MainWindow(QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.mdi = QMdiArea()
self.setCentralWidget(self.mdi)
fileOpenAction = QAction("&Open...", self)
fileOpenAction.setShortcut(QKeySequence.Open)
fileOpenAction.triggered.connect(self.fileOpen)
fileMenu = self.menuBar().addMenu("&File")
fileMenu.addAction(fileOpenAction)
settings = QSettings()
self.restoreGeometry(settings.value("MainWindow/Geometry",
QByteArray()))
self.restoreState(settings.value("MainWindow/State",
QByteArray()))
QTimer.singleShot(0, self.loadFiles)
def loadFiles(self):
if len(sys.argv) > 1:
for filename in sys.argv[1:31]: # Load at most 30 files
if QFileInfo(filename).isFile():
self.loadFile(filename)
QApplication.processEvents()
else:
settings = QSettings()
files = settings.value("CurrentFiles") or []
for filename in files:
if QFile.exists(filename):
self.loadFile(filename)
QApplication.processEvents() #todo What does this do?
def fileOpen(self):
filename, _ = QFileDialog.getOpenFileName(self,
"Text Editor -- Open File")
if filename:
for textEdit in self.mdi.subWindowList():
print(type(textEdit))
if textEdit.filename == filename:
self.mdi.setActiveSubWindow(textEdit)
break
else:
self.loadFile(filename)
def loadFile(self, filename):
textEdit = TextEdit(filename)
try:
textEdit.load()
except EnvironmentError as e:
QMessageBox.warning(self, "Text Editor -- Load Error",
"Failed to load {}: {}".format(filename, e))
textEdit.close()
del textEdit
else:
self.mdi.addSubWindow(textEdit)
textEdit.show()
app = QApplication(sys.argv)
app.setWindowIcon(QIcon(":/icon.png"))
app.setOrganizationName("Qtrac Ltd.")
app.setOrganizationDomain("qtrac.eu")
app.setApplicationName("Text Editor")
form = MainWindow()
form.show()
app.exec_()
The problem occurs in the fileOpen() method:
PyQt4 fileOpen() method
def fileOpen(self):
filename = QFileDialog.getOpenFileName(self,
"Text Editor -- Open File")
if filename:
for textEdit in self.mdi.windowList():
if textEdit.filename == filename:
self.mdi.setActiveWindow(textEdit)
break
else:
self.loadFile(filename)
PyQt5 fileOpen() method
def fileOpen(self):
filename, _ = QFileDialog.getOpenFileName(self,
"Text Editor -- Open File")
if filename:
for textEdit in self.mdi.subWindowList():
if textEdit.filename == filename:
self.mdi.setActiveSubWindow(textEdit)
break
else:
self.loadFile(filename)
windowList() is implemented in PyQt5 as subWindowList(). The problem is that in the PyQt4 version, when for textEdit in self.mdi.windowList(): is executed textEdit is of type TextEdit so the next line
if textEdit.filename == filename
works since TextEdit does have a filename parameter. and textEdit is a {TextEdit}textedit.TextEdit object, but in the PyQt5 version, after for textEdit in self.mdi.subWindowList(): is executed, the type of textEdit is QMdiSubWindow so, of course the traceback generates:
Traceback (most recent call last):
File "texteditor3.py", line 292, in fileOpen
if textEdit.filename == filename:
AttributeError: 'QMdiSubWindow' object has no attribute 'filename'
What really baffles me is how textEdit in the PyQt4 version becomes a TextEdit type. I would think it would be a str type.

I'am from Germany I found an answer. See the Code.
Sorry about the German Comments.
def fileOpen(self):
try:
# PSc QFileDialog.getOpenFileName gibt ein Tuple zurück
# für die weitere Verwendung filname[0] verwenden
filename = QFileDialog.getOpenFileName(self,
"Text Editor -- Open File")
if filename:
try:
# PSc wenn ein zweites Open durchgeführt wird erhält man die Fehlermeldung
# textEdit has no attribute fileName
# http://stackoverflow.com/questions/37800036/porting-pyqt4-qworkspace-to-pyqt5-qmdiarea-subwindowlist-method
# Lösung scheinbar hier gefunden Zeile 268 269
# http://nullege.com/codes/show/src%40p%40y%40pyqt5-HEAD%40examples%40mainwindows%40mdi%40mdi.py/168/PyQt5.QtWidgets.QMdiArea.subWindowActivated.connect/python
# Folgende Zeile dementsprechen geändert
# for textEdit in self.mdi.subWindowList():
for windows in self.mdi.subWindowList():
textEdit = windows.widget()
print('In File Open textEdit.filename: ' + textEdit.filename)
if textEdit.filename == filename[0]:
self.mdi.setActiveWindow(textEdit)
break
else:
# PSc filename Tuple daher filename[0] übergeben
self.loadFile(filename[0])
except:
e = sys.exc_info()
print('An exception occurred in def fileOpen if Filename : \n' + str(e) + '\n')
except:
e = sys.exc_info()
print('An exception occurred in def fileOpenin: \n' + str(e) + '\n')
I Have changed it everywher like:
def fileSave(self):
try:
# PSc PyQt4 Syntax
# textEdit = self.mdi.activeSubWindow()
# geändert laut Zeile 268,269
# nullege.com/codes/show/src%40p%40y%40pyqt5-HEAD%40examples%40mainwindows%40mdi%40mdi.py/168/PyQt5.QtWidgets.QMdiArea.subWindowActivated.connect/python
window = self.mdi.activeSubWindow()
textEdit = window.widget()
if textEdit is None or not isinstance(textEdit, QTextEdit):
return True
try:
textEdit.save()
return True
except EnvironmentError as e:
QMessageBox.warning(self, "Text Editor -- Save Error",
"Failed to save {}: {}".format(textEdit.filename, e))
return False
except Exception as error:
print('An exception occurred in fileSave: {}'.format(error))

Related

Python watchdog module duplicate events (edit: was not an watchdog issue)

I am creating a python script that will identify changes to a log file and print some data from the new logs.
I use watchdog to create an event handler and everything seems to work fine except from that, I get duplicate events every time I modify the file. I checked creation and delete, they both work as expected and trigger one time.
I have read the similar question which explains having a created and a modified event when I save a file but this is not my case. I just get two modification events.
Here is my code:
import os, sys, time
import subprocess
import threading
import win32print
from tkinter import filedialog
from tkinter import *
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler
class Handler(FileSystemEventHandler):
# docstring for FileSystemEventHandler
def __init__(self, observer, filename, dirname):
# super(Handler, FileSystemEventHandler).__init__(self,)
self.observer = observer
self.filename = filename
self.dirname = dirname
print("Handler filename = " , self.filename)
print("Handler dirname = " , self.dirname)
def on_modified(self, event):
if self.filename == event.src_path:
print("The file was modified")
print (event.src_path)
# go get the last line and print the data
# try:
# hJob = win32print.StartDocPrinter (hPrinter, 1, ("test of raw data", None, "RAW"))
# try:
# win32print.StartPagePrinter (hPrinter)
# win32print.WritePrinter (hPrinter, raw_data)
# win32print.EndPagePrinter (hPrinter)
# finally:
# win32print.EndDocPrinter (hPrinter)
# finally:
# win32print.ClosePrinter (hPrinter)
def on_created(self, event):
print("A file was created (", event.src_path, ")")
def on_deleted(self, event):
print("A file was deleted (", event.src_path, ")")
if __name__ == "__main__":
Flags=2
Name=None
Level=1
printers = win32print.EnumPrinters(Flags, Name, Level)
print("\nChoose a printer to use:")
i=1
for p in printers:
print(i,')' , p[2])
i = i+1
if sys.version_info >= (3,):
raw_data = bytes ("This is a test", "utf-8")
else:
raw_data = "This is a test"
printer = int(input())
printer_name = printers[printer-1][2] #win32print.GetDefaultPrinter ()
print("You chose ", printer_name, "\nI will now print from the specified file with this printer")
hPrinter = win32print.OpenPrinter (printer_name)
# root = Tk()
# root.filename = filedialog.askopenfilename(initialdir = "/Desktop",title = "Select file",filetypes = (("log files","*.log"),("all files","*.*")))
file_path = "some_file_path" # root.filename
file_directory = os.path.dirname(file_path)
# print (file_path)
print (file_directory)
observer = Observer()
event_handler = Handler(observer, file_path, file_directory)
observer.schedule(event_handler, path=file_directory, recursive=False)
observer.start()
observer.join()
any ideas would be appreciated
EDIT:
After some debugging I found out that Windows10 is changing the file modification time twice every time I save it.
The proof of concept code is this:
prev_modification_time = os.path.getmtime(file_path)
while True:
current_mod_time = os.path.getmtime(file_path)
if prev_modification_time != current_mod_time :
print ("the file was modified, last modification time is: ", current_mod_time)
prev_modification_time = current_mod_time
pass
Final edit:
After testing my code on linux (Debian Stretch to be exact) it worked like a charm. So this combined with the previous edit probably shows that watchdog works fine and it is windows10 that has some issue. Should I post it on a different question or here?

Drag and drop in QTreeView fails with items that hold a QImage

I have a list of items in a QTreeView. Each item holds a QImage object. If I try to drag and drop the item, the program freezes. But when I comment out the line objMod._Image = QImage(flags = Qt.AutoColor), the program runs fine.
How can I drag and drop the items with the QImage object? The QImage holds an image which is rendered. The rendering process takes a while, so it would be nice to keep the QImage object.
import sys
import os
from PySide.QtCore import *
from PySide.QtGui import *
from PySide.QtUiTools import *
from PIL import Image, ImageCms, ImageQt
class ObjModel:
def __init__(self):
self._Image = None
class DragMoveTest(QMainWindow):
def __init__(self):
super(DragMoveTest,self).__init__()
self.initGUI()
self.show()
def initGUI(self):
self.treeView = QTreeView()
modelTreeView = QStandardItemModel()
self.treeView.setModel(modelTreeView)
for i in range(0, 4):
objMod = ObjModel()
objMod._Image = None
objMod._Image = QImage(flags = Qt.AutoColor)
item = QStandardItem('Test: %s' % str(i))
item.setData(objMod, Qt.UserRole + 1)
modelTreeView.invisibleRootItem().appendRow(item)
self.treeView.setDragDropMode(QAbstractItemView.InternalMove)
self.setCentralWidget(self.treeView)
def main(args):
app = QApplication(sys.argv)
qt_main_wnd = DragMoveTest()
ret = app.exec_()
sys.exit(ret)
if __name__ == "__main__":
main(sys.argv)
This is caused by a bug in PySide. During a drag and drop operation, the data in the dragged item must be serialized. This will be handled by Qt for most data-types, but for types that are specific to Python, special handling is required. This special handling seems to be broken in PySide. If your example is converted to PyQt, a TypeError is raised when trying to drag items, but the program does not freeze.
The source of the problem is that you are storing data using a custom Python class. PyQt uses pickle to serialize custom data-types, but it is not possible to also pickle the QImage that is stored in its __dict__, so the operation fails. I assume PySide must attempt something similar, but for some reason it does not raise an error when it fails. Qt grabs the mouse whilst dragging, so if the operation fails abnormally, it won't be released again, and the program will appear to freeze.
The simplest way to fix this is to avoid using a custom class to hold the QImage, and instead store the image directly in the item:
image = QImage()
item = QStandardItem('Test: %s' % i)
item.setData(image, Qt.UserRole + 1)
To store more data items, you can either use a different data-role for each one, or use a dict to hold them all:
data = {'image': QImage(), 'title': 'foo', 'timestamp': 1756790}
item.setData(data, Qt.UserRole + 1)
However, if you do this, you must always use string keys in the dict, otherwise you will face the same problems as before. (Using string keys means the dict can be converted into a QMap, which Qt knows how to serialize).
(NB: if you want to know whether a Qt class can be serialized, check the docs to see whether it defines the datastream operators).
I come up with a different solution. It is easier to have a object that holds a io.BytesIO. Your store the ImageData into the bytesIO variable. Upon on your image library you can open the image from the bytesIO variable.
In the demo the class ObjModel can handle QImage and Image from Pillow/PIL. If you use the set methods the image object will be converted into a bytesIO.
In short here a working example:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import sys
import os
import io
from PySide.QtCore import *
from PySide.QtGui import *
from PySide.QtUiTools import *
from PIL import Image, ImageCms, ImageQt
########################################################################
class ObjModel:
""""""
#----------------------------------------------------------------------
def __init__(self):
"""Constructor"""
self._ImageByteIO = None
#----------------------------------------------------------------------
def getObjByte(self):
""""""
return self._ImageByteIO
#----------------------------------------------------------------------
def getQImage(self):
""""""
try:
self._ImageByteIO.seek(0)
qImg = QImage.fromData(self._ImageByteIO.getvalue())
return qImg
except:
return None
#----------------------------------------------------------------------
def getPILImage(self):
""""""
try:
self._ImageByteIO.seek(0)
img = Image.open(tBytesIO)
return img
except:
return None
#----------------------------------------------------------------------
def setObjByte(self, fileName):
""""""
try:
tBytesIO = io.BytesIO()
f = open (fileName, 'rb')
tBytesIO.write(f.read())
f.close()
self._ImageByteIO = tBytesIO
except:
self._ImageByteIO = None
#----------------------------------------------------------------------
def setQImage(self, qImg):
""""""
try:
tBytesIO = io.BytesIO()
qByteArray = QByteArray()
qBuf = QBuffer(qByteArray)
qBuf.open(QIODevice.ReadWrite)
qImg.save(qBuf, 'PNG')
tBytesIO = io.BytesIO()
tBytesIO.write(qByteArray.data())
self._ImageByteIO = tBytesIO
except:
self._ImageByteIO = None
#----------------------------------------------------------------------
def setPILImage(self, pImg):
""""""
tBytesIO = io.BytesIO()
pImg.save(tBytesIO, 'png')
self._ImageByteIO = tBytesIO
#----------------------------------------------------------------------
class DragMoveTest(QMainWindow):
def __init__(self):
""""""
super(DragMoveTest,self).__init__()
self.initGUI()
self.show()
#----------------------------------------------------------------------
def initGUI(self):
""""""
self.treeView = QTreeView()
modelTreeView = QStandardItemModel()
self.treeView.setModel(modelTreeView)
for i in range(0, 4):
objMod = ObjModel()
objMod.setQImage(QImage(flags = Qt.AutoColor))
item = QStandardItem('Test: %s' % str(i))
item.setData(objMod, Qt.UserRole + 1)
modelTreeView.invisibleRootItem().appendRow(item)
self.treeView.setDragDropMode(QAbstractItemView.InternalMove)
self.setCentralWidget(self.treeView)
#----------------------------------------------------------------------
def main(args):
app = QApplication(sys.argv)
qt_main_wnd = DragMoveTest()
ret = app.exec_()
sys.exit(ret)
#----------------------------------------------------------------------
if __name__ == "__main__":
main(sys.argv)

'Close window' button wont work when using tkinter + gobject

My tkinter application runs fine, but to implement dbus functionality I had to use gobject. Got it working and all, except that, running both tkinter's and gobject's mainloops makes the "close window" button from the standard window manager ('x' button in the window interface) not to work. :/ Everything else works fine, including resizing, minimizing/maximizing, restoring, and moving the window.
Any help is appreciated,
Thanks,
Little code snippet:
import dbus
from dbus.service import Object
from dbus.mainloop.glib import DBusGMainLoop
class TBOPlayerDBusInterface (Object):
tboplayer_instance = None
def __init__(self, tboplayer_instance):
self.tboplayer_instance = tboplayer_instance
dbus_loop = DBusGMainLoop()
bus_name = dbus.service.BusName("org.tboplayer.TBOPlayer", bus = dbus.SessionBus(mainloop = dbus_loop))
Object.__init__(self, bus_name, "/org/tboplayer/TBOPlayer")
#dbus.service.method('org.tboplayer.TBOPlayer', in_signature = 'as')
def openFiles(self, files):
self.tboplayer_instance._add_files(files)
# ***************************************
# MAIN
# ***************************************
if __name__ == "__main__":
datestring=" 28 Fev 2017"
dbusif_tboplayer = None
try:
bus = dbus.SessionBus()
bus_object = bus.get_object("org.tboplayer.TBOPlayer", "/org/tboplayer>/TBOPlayer", introspect = False)
dbusif_tboplayer = dbus.Interface(bus_object, "org.tboplayer.TBOPlayer")
except Exception, e:
print e
if dbusif_tboplayer is None:
tk.CallWrapper = ExceptionCatcher
bplayer = TBOPlayer()
TBOPlayerDBusInterface(bplayer)
def refresh_player():
bplayer.root.update()
return True
def run_gobject():
gobject.MainLoop().run()
gobject.idle_add(refresh_player)
bplayer.root.after(100, run_gobject)
bplayer.root.mainloop()
else:
if len(sys.argv[1:]) > 0:
dbusif_tboplayer.openFiles(sys.argv[1:])
exit()
I found the problem. For some reason, using tkinter's and gobject's mainloops interferes with the behavior of the WM_DELETE_WINDOW event, which I was using for saving some data before closing the program. Solved the problem by binding to the Configure event instead. And now the main method is as follows:
if __name__ == "__main__":
datestring=" 28 Fev 2017"
dbusif_tboplayer = None
try:
bus = dbus.SessionBus()
bus_object = bus.get_object("org.tboplayer.TBOPlayer", "/org/tboplayer/TBOPlayer", introspect = False)
dbusif_tboplayer = dbus.Interface(bus_object, "org.tboplayer.TBOPlayer")
except Exception, e:
print e
if dbusif_tboplayer is None:
tk.CallWrapper = ExceptionCatcher
bplayer = TBOPlayer()
TBOPlayerDBusInterface(bplayer)
gobject_loop = gobject.MainLoop()
def refresh_player():
try:
bplayer.root.update()
return True
except Exception, e:
bplayer.quit_omx()
gobject_loop.quit()
def run_gobject():
gobject_loop.run()
gobject.idle_add(refresh_player)
bplayer.root.after(100, run_gobject)
bplayer.root.mainloop()
else:
if len(sys.argv[1:]) > 0:
dbusif_tboplayer.openFiles(sys.argv[1:])
exit()

How can I save output tho the same file that I have got the data from, in Python 3

I am trying to open a file, remove some characters (defined in dic) and then save it to the same the file.
I can print the output and it looks fine, but I cannot save it into the same file that the original text is being loaded from.
from tkinter import *
from tkinter.filedialog import askopenfilename
from tkinter.messagebox import showerror
import sys
import fileinput
dic = {'/':' ', '{3}':''};
def replace_all(text, dic):
for i, j in dic.items():
text = text.replace(i, j)
return text
class MyFrame(Frame):
def __init__(self):
Frame.__init__(self)
self.master.title("Example")
self.master.rowconfigure(5, weight=1)
self.master.columnconfigure(5, weight=1)
self.grid(sticky=W+E+N+S)
self.button = Button(self, text="Browse", command=self.load_file, width=10)
self.button.grid(row=1, column=0, sticky=W)
def load_file(self):
fname = askopenfilename(filetypes=(("Napisy", "*.txt"),
("All files", "*.*") ))
if fname:
try:
with open (fname, 'r+') as myfile: #here
data = myfile.read() #here
data2 = replace_all(data, dic) #here
print(data2) #here
data.write(data2) #and here should it happen
except:
showerror("Open Source File", "Failed to read file\n'%s'" % fname)
return
if __name__ == "__main__":
MyFrame().mainloop()
I have tried several commands but either I am receiving python errors or it is simply not working.
This is often implemented by writing to a temp file and then moving it to the original file's name.
Strings do not have a .write method. The following should work (I tried it): replace
data.write(data2) #and here should it happen
with
myfile.seek(0)
myfile.truncate()
myfile.write(data2)
The truncate() call is needed if data2 is shorter than data as otherwise, the tail end of data will be left in the file.

why can't I change self.filename?

I created a simple server/client app using PyQt.But I got strange error:
here is my server side code:
#! /usr/bin/python
import sys
import socket
from PyQt4.QtCore import *
from PyQt4.QtGui import *
from PyQt4.QtNetwork import *
HOST = '127.0.0.1'
PORT = 9991
SIZEOF_UINT32 = 4
class Form(QDialog):
def __init__(self, parent=None):
super(Form, self).__init__(parent)
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.socket.bind((HOST, PORT))
self.socket.listen(5)
self.worker = Worker(self.socket)
self.connect(self.worker, SIGNAL("received"), self.updateUi)
self.connect(self.worker, SIGNAL("finished()"), self.updateUi)
self.connect(self.worker, SIGNAL("terminated()"), self.updateUi)
# Create widgets/layout
self.browser = QTextBrowser()
self.selectButton = QPushButton('Close server')
layout = QVBoxLayout()
layout.addWidget(self.browser)
layout.addWidget(self.selectButton)
self.setLayout(layout)
self.setWindowTitle("Server")
self.worker.start()
def updateUi(self, text):
self.browser.append(text)
class Worker(QThread):
def __init__(self,socket,parent = None):
super(Worker, self).__init__(parent)
self.socket = socket
self.dir = '/home/jacos/down/'
self.filename = '/home/jacos/down/hello'
def receiveFile(self):
self.conn, self.addr = self.socket.accept()
totalData = ''
while 1:
data = self.conn.recv(1024)
if not data: break
totalData += data
print totalData
if totalData.find('f') == 0:
name = totalData.strip()[1:]
self.filename = self.dir + name
print self.filename
else:
self.saveFile(totalData)
print self.filename
self.emit(SIGNAL("received"),QString("received a file"))
def saveFile(self,data):
f = open(self.filename,'wb')
print self.filename
f.write(data)
f.close()
self.conn.close()
def run(self):
while 1:
self.receiveFile()
app = QApplication(sys.argv)
form = Form()
form.show()
app.exec_()
When I run it,I got this:
Traceback (most recent call last):
File "/home/jacos/bin/tss.pyw", line 75, in run
self.receiveFile()
File "/home/jacos/bin/tss.pyw", line 61, in receiveFile
self.saveFile(totalData)
File "/home/jacos/bin/tss.pyw", line 66, in saveFile
f = open(self.filename,'wb')
TypeError: file() argument 1 must be encoded string without NULL bytes, not str
TypeError: updateUi() takes exactly 2 arguments (1 given)
The problem is all about self.filename.It seems I can't pass it with the correct value...
Here is my client side code:
#! /usr/bin/python
# -*- coding: utf8 -*-
import sys
import socket
from PyQt4.QtCore import *
from PyQt4.QtGui import *
from PyQt4.QtNetwork import *
HOST = '127.0.0.1'
PORT = 9991
SIZEOF_UINT32 = 4
class Form(QDialog):
def __init__(self, parent=None):
super(Form, self).__init__(parent)
# Create widgets/layout
self.browser = QTextBrowser()
self.selectButton = QPushButton('Send a File')
self.connectButton = QPushButton("Connect")
self.connectButton.setEnabled(True)
layout = QVBoxLayout()
layout.addWidget(self.browser)
layout.addWidget(self.selectButton)
layout.addWidget(self.connectButton)
self.setLayout(layout)
# Signals and slots for line edit and connect button
self.selectButton.clicked.connect(self.sendFileName)
self.connectButton.clicked.connect(self.connectToServer)
self.setWindowTitle("Client")
# Update GUI
def updateUi(self, text):
self.browser.append(text)
def sendFileName(self):
filename=QFileDialog.getOpenFileName(self, 'Open File', '.')
name = filename.split('/')[-1]
self.updateUi("Sent file name:" + name)
self.socket.sendall("f" + name)
self.socket.close()
self.connectToServer()
self.sendFile(filename,name)
def sendFile(self,filename,name):
self.socket.sendall(open(filename,'rb').read())
self.updateUi("Sent file:" + filename)
self.socket.close()
self.connectButton.setEnabled(True)
def connectToServer(self):
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.socket.connect((HOST, PORT))
self.connectButton.setEnabled(False)
self.updateUi("Connected")
app = QApplication(sys.argv)
form = Form()
form.show()
app.exec_()
Thanks for any help.
You probably have a NULL byte (\0 or \x00) in self.filename and as the error indicates, you can't open a file with the name containing NULL byte. Deal with them appropriately beforehand (eg: remove, replace, etc.).
As for the other error: You are connecting two signals (finished and terminated) to self.updateUi. And these signals doesn't have pass any arguments whereas self.updateUi expects an argument to be passed, namely text. I'm not sure what your goal is but you might consider adding a default argument for the text parameter in self.updateUi.

Resources