I wrote this code, it's supposed to be a clipart browser (locked to "klip" folder under current directory).
When I start add signal at folder button (dbutton) I screw up: I don't know how to refresh the toolitemgroup content and icons keep appended, I can't remove manually since the button generated in loop.
And one more, how can I "auto-fit/trim" the button label? Cause it grows insane if the filename is lengthy.
import gtk
from os.path import join,normpath,splitext, isdir
from os import getcwd, walk, mkdir
klip="klip"
klipdir=join(getcwd(),klip)
#init dir
if not isdir(klipdir):
mkdir(klipdir)
class kaosmu:
def icon_builder_cb(self, widget, data=klip):
if data != klip:
homebutton = gtk.ToolButton(gtk.STOCK_HOME)
browser.add(homebutton)
upbutton = gtk.ToolButton(gtk.STOCK_GO_UP)
browser.add(upbutton)
#folder
idx=dirs.index(data)
print idx
for i in dirs[idx+1]:
dbutton = gtk.ToolButton(gtk.STOCK_OPEN)
dbutton.set_label(i)
dbutton.connect("clicked", self.icon_builder_cb, join(data,i))
browser.add(dbutton)
#files
for i in dirs[idx+2]:
pixbuf = gtk.gdk.pixbuf_new_from_file_at_size(join(data,i),32,32)
img=gtk.Image()
img.set_from_pixbuf(pixbuf)
svg = gtk.ToolButton(img,splitext(i)[0])
browser.add(svg)
browser.show_all()
def im_browser_cb(self, widget, data=klipdir):
global dirs
dirs = []
for (p, d, f) in walk(data):
key=p[len(data)-len(klip):]
dirs.append(key)
dirs.append(d)
dirs.append(f)
def __init__(self):
self.im_browser_cb(None)
window = gtk.Window()
window.set_default_size(1024, 800)
window.set_border_width(2)
window.connect("destroy", lambda w: gtk.main_quit())
drawingarea = gtk.DrawingArea()
drawingarea.set_size_request(600, 700)
hpane = gtk.HPaned()
menuscroll = gtk.ScrolledWindow()
canvasscroll = gtk.ScrolledWindow()
toolpalette = gtk.ToolPalette()
toolpalette.set_style(gtk.TOOLBAR_BOTH)
toolpalette.set_icon_size(gtk.ICON_SIZE_DND)
hpane.set_position(250)
window.add(hpane)
hpane.add1(menuscroll)
hpane.add2(canvasscroll)
menuscroll.add_with_viewport(toolpalette)
canvasscroll.add_with_viewport(drawingarea)
global browser
browser = gtk.ToolItemGroup(" Browser ")
toolpalette.add(browser)
toolpalette.set_expand(browser, True)
self.icon_builder_cb(None)
window.show_all()
def main(self):
gtk.main()
if __name__ == "__main__":
kaos = kaosmu()
kaos.main()
I solved this with:
while browser.get_nth_item(0):
browser.remove(browser.get_nth_item(0))
Related
I'm following this tutorial for a PyQt5 GUI window:
Here's My code on pastebin.
import sys
from PyQt5 import QtWidgets, QtGui
def window1():
app = QtWidgets.QApplication(sys.argv)
w = QtWidgets.QWidget()
b = QtWidgets.QPushButton('Comparison Report', w)
l1 = QtWidgets.QLabel(w)
l2 = QtWidgets.QLabel(w)
l1.setText('Main Page')
b.setGeometry(200, 100, 300, 70)
w.setWindowTitle('Diff Util')
w.setGeometry(800, 200, 720, 800)
l1.move(310, 5)
w.show()
sys.exit(app.exec_())
#import file_report
#def on_click(self):
#file_report()
window1()
Here's a comparison file script also on pastebin... but i Need 10rep to link it >_>
import sys
import os
import difflib
first_file = input("Select original file: ")
second_file = input("Select second file for comparison: ")
first_file_lines = open(first_file).readlines()
second_file_lines = open(second_file).readlines()
difference = difflib.HtmlDiff(tabsize=8,
wrapcolumn=100).make_file(first_file_lines, second_file_lines, first_file, second_file, charset='utf-8')
difference_report = open('difference_report.html', 'w')
difference_report.write(difference)
difference_report.close()
os.startfile('difference_report.html')
My question is, how to connect my file_report.py to the pushbutton I've created with PyQt5?
As you can see I commented out "import file_report" because from my understanding I'm supposed to import my script... but the import causes it to run the script in terminal, and after execution will open my GUI. I would like to run this script, but contain it within the GUI window I've created instead of opening a terminal for execution.
So where in the PyQt5 script should I import, and include the .py file?
GUIs are not friendly with blocking tasks since for their existence they create a loop. Therefore the function input() should not be used, the solution to use elements provided by the library as QLineEdit, PyQt also provides dialog boxes for the selection of files.
import sys
from PyQt5 import QtWidgets, QtGui, QtCore
import difflib
class Widget(QtWidgets.QWidget):
def __init__(self, parent=None):
QtWidgets.QWidget.__init__(self, parent)
self.setLayout(QtWidgets.QGridLayout())
self.le1 = QtWidgets.QLineEdit("", self)
self.le2 = QtWidgets.QLineEdit("", self)
self.le3 = QtWidgets.QLineEdit("", self)
self.btn1 = QtWidgets.QPushButton("Select first file")
self.btn2 = QtWidgets.QPushButton("Select second file")
self.btn3 = QtWidgets.QPushButton("Select save File")
self.btnRun = QtWidgets.QPushButton("Run")
self.layout().addWidget(self.le1, 1, 1)
self.layout().addWidget(self.le2, 2, 1)
self.layout().addWidget(self.le3, 3, 1)
self.layout().addWidget(self.btn1, 1, 2)
self.layout().addWidget(self.btn2, 2, 2)
self.layout().addWidget(self.btn3, 3, 2)
self.layout().addWidget(self.btnRun, 4, 2)
self.btnRun.clicked.connect(self.onRun)
self.btn1.clicked.connect(self.selectFirstFile)
self.btn2.clicked.connect(self.selectSecondFile)
self.btn3.clicked.connect(self.selectSaveFile)
def selectFirstFile(self):
filename, _ = QtWidgets.QFileDialog.getOpenFileName(self, "Select Files", QtCore.QDir.currentPath(), "*.html")
if filename != "":
self.le1.setText(filename)
def selectSecondFile(self):
filename, _ = QtWidgets.QFileDialog.getOpenFileName(self, "Select Files", QtCore.QDir.currentPath(), "*.html")
if filename != "":
self.le2.setText(filename)
def selectSaveFile(self):
filename, _ = QtWidgets.QFileDialog.getSaveFileName(self, "Select Files", QtCore.QDir.currentPath(), "*.html")
if filename != "":
self.le3.setText(filename)
def onRun(self):
first_file = self.le1.text()
second_file = self.le2.text()
output_file = self.le3.text()
first_file_lines = open(first_file).readlines()
second_file_lines = open(second_file).readlines()
difference = difflib.HtmlDiff(tabsize=8, wrapcolumn=100).make_file(first_file_lines, second_file_lines, first_file, second_file, charset='utf-8')
difference_report = open(output_file, 'w')
difference_report.write(difference)
difference_report.close()
QtGui.QDesktopServices.openUrl(QtCore.QUrl.fromLocalFile(output_file))
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
w = Widget()
w.show()
sys.exit(app.exec_())
How can I trigger the changing of an icon when the user clicks the Icon only for the items/rows in the list which are of type File. Each row in the treeview contains an object in the UserRole called TreeItem which stores if the item is marked as a favorite and also the filepath.
In short is there a way to know if a the Decoration 'icon' is clicked by the user?
The tool simply just goes through a directory recursively and collects the files and folders.
class TreeItem(object):
def __init__(self, filepath):
self.filepath = filepath
self.isFavorite = False
Dropbox links to icons
https://www.dropbox.com/s/3pt0ev2un7eoswh/file_off.svg?dl=0
https://www.dropbox.com/s/xext3m9d4atd3i6/file_on.svg?dl=0
https://www.dropbox.com/s/6d750av0y77hq0g/folder.svg?dl=0
Be sure to change the directory path for testing
Tool Code:
import sys
import os
from PySide import QtGui, QtCore, QtSvg
DIR_ICON_PATH = 'folder.svg'
FILE_ICON_OFF = 'file_off.svg'
FILE_ICON_ON = 'file_on.svg'
class TreeItem(object):
def __init__(self, filepath):
self.filepath = filepath
self.isFavorite = False
class Example(QtGui.QWidget):
def __init__(self):
super(Example, self).__init__()
self.initUI()
def initUI(self):
# formatting
self.resize(550, 400)
self.setWindowTitle("Toychest")
# widgets
self.treeview = QtGui.QTreeView()
self.treeview.setHeaderHidden(True)
self.treeview.setUniformRowHeights(True)
self.treeview.setEditTriggers(QtGui.QAbstractItemView.NoEditTriggers)
self.source_model = QtGui.QStandardItemModel()
self.treeview.setModel(self.source_model)
# signals
self.treeview.doubleClicked.connect(self.doubleClickedItem)
# main layout
mainLayout = QtGui.QGridLayout()
mainLayout.setContentsMargins(0,0,0,0)
mainLayout.addWidget(self.treeview)
self.setLayout(mainLayout)
self.initDirectory('C:/Users/jmartini/Downloads')
# Functions
# ------------------------------------------------------------------------------
def initDirectory(self, path):
new_item = self.newItem(path)
self.readDirectory(path, new_item)
self.source_model.appendRow(new_item)
def readDirectory(self, path, parent_item):
directory = os.listdir(path)
for file_name in directory:
file_path = path + '/' + file_name
new_item = self.newItem(file_path)
parent_item.appendRow(new_item)
if os.path.isdir(file_path):
self.readDirectory(file_path, new_item)
def newItem(self, path):
# create Object
obj = TreeItem(path)
title = os.path.basename(path)
item = QtGui.QStandardItem()
item.setData(obj, role=QtCore.Qt.UserRole)
icon_path = FILE_ICON_OFF
if os.path.isdir(path):
icon_path = DIR_ICON_PATH
icon = QtGui.QIcon(icon_path)
item.setText(title)
item.setIcon(icon)
return item
def doubleClickedItem(self, idx):
if not idx.isValid():
return
obj = idx.data(QtCore.Qt.UserRole)
print obj.filepath, obj.isFavorite
# print idx.parent(), idx.parent().isValid()
# model = idx.model()
# print model.index(idx.row(), 0, parent=idx.parent()).data()
# Main
# ------------------------------------------------------------------------------
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
ex = Example()
ex.show()
sys.exit(app.exec_())
You have to implement the mousePressEvent and compare the mouse position with icon position and proceed accordingly.
You can use QStandardItemModel.itemFromIndex in order to access to the underlying item. The model can be obtained via QModelIndex.model. So the following would do:
item = idx.model().itemFromIndex(idx)
obj = idx.data(QtCore.Qt.UserRole).toPyObject()
obj.isFavorite = (obj.isFavorite + 1) % 2
if obj.isFavorite:
item.setIcon(QtGui.QIcon(FILE_ICON_ON))
else:
item.setIcon(QtGui.QIcon(FILE_ICON_OFF))
If required you can access obj.filepath in order to check whether the clicked item corresponds to a file.
I've noticed that, using the following code, if you choose to click "Cancel" on the FileDialog for "Import File", the entire application closes instead of returning to the menu and awaiting a different choice. How can I get it to just return to the mainMenu?
(Note: I've noticed if I don't put anything after the initial file dialog call, it functions fine.)
Code:
import sys
import xml.etree.ElementTree as et
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
class MainMenu(QDialog):
def __init__(self):
QDialog.__init__(self)
layout = QGridLayout()
# Create Objects for Main Menu
logoLabel = QLabel("TESTAPP")
logoFont = QFont("Broadway", 48)
logoLabel.setFont(logoFont)
versionLabel = QLabel("Version 0.1a")
copyrightLabel = QLabel("Copyright 2016")
importButton = QPushButton("Import File")
quitButton = QPushButton("Quit")
# Set Locations of Widgets
layout.addWidget(logoLabel, 0, 0)
layout.addWidget(versionLabel, 1, 0)
layout.addWidget(copyrightLabel, 2, 0)
layout.addWidget(importButton, 4, 0)
layout.addWidget(quitButton, 5, 0)
self.setLayout(layout)
self.setWindowTitle("NESSQL")
# Connect Buttons to Actions
importButton.clicked.connect(self.importFile)
quitButton.clicked.connect(self.close)
def importFile(self):
# Open dialog box to get the filename
file = QFileDialog.getOpenFileName(self, caption="File to Import", directory=".",
filter="All Files (*.*)")
data = et.parse(file)
root = data.getroot()
if __name__ == '__main__':
app = QApplication(sys.argv)
mainMenu = MainMenu()
mainMenu.show()
app.exec_()
by keeping condition for checking whether file is empty or not you can avoid this issue.
It goes something like this in your case.
def importFile(self):
# Open dialog box to get the filename
file = QFileDialog.getOpenFileName(self, caption="File to Import",
directory=".",filter="All Files (*.*)")
if not file[0] == "":
data = et.parse(file)
root = data.getroot()
saran vaddi's answer didn't work for me but this did:
def importFile(self):
# Open dialog box to get the filename
file = QFileDialog.getOpenFileName(self, caption="File to Import", directory=".", filter="All Files (*.*)")
# If file is blank, simply return control to calling function
if not file:
return
I am trying to create a button in a window that will ultimately run a function that I have written from code. My GUI code so far is as follows:
import sys
from PyQt4 import QtGui, QtCore
class PAINSFILTER(QtGui.QMainWindow):
def __init__(self):
QtGui.QWidget.__init__(self)
# Layout Init.
self.setGeometry (650, 300, 600, 600)
self.setWindowTitle('Data Viewer')
self.setWindowIcon(QtGui.QIcon('pill.png'))
extractAction = QtGui.QAction("Quit", self)
extractAction.setShortcut("Ctrl+Q")
extractAction.setStatusTip('Leave App')
extractAction.triggered.connect(self.close_application)
self.statusBar()
mainMenu = self.menuBar()
fileMenu = mainMenu.addMenu("&File")
fileMenu.addAction(extractAction)
self.uploadButton = QtGui.QPushButton('UPLOAD SDF', self)
self.runfilterButton = QtGui.QPushButton('Run Filter', self)
self.uploadButton.move (200, 50)
self.runfilterButton.move (400,50)
hBoxLayout = QtGui.QHBoxLayout()
hBoxLayout.addWidget(self.uploadButton)
hBoxLayout.addWidget(self.runfilterButton)
self.setLayout(hBoxLayout)
# Signal Init.
self.connect(self.uploadButton, QtCore.SIGNAL('clicked()'), self.open)
def open (self):
filename = QtGui.QFileDialog.getOpenFileName(self, 'Open File', '.')
print 'Path file:', filename
def close_application(self):
print ("Out")
sys.exit()
def run():
app = QtGui.QApplication(sys.argv)
mw = PAINSFILTER()
mw.show()
sys.exit(app.exec_())
run()
The function I am trying to run through the button is a simple nested loop that will take the file I uploaded through the "upload sdf" button and run it through that function. How do I link that function to a button using PyQt. Here is the function for reference:
suppl = Chem.SDMolSupplier('data.sdf') #this .sdf file is the one uploaded through the upload sdf button
for m in suppl:
for x in range(len(pains_smarts)):
if m.HasSubstructMatch(Chem.MolFromSmarts(pains_smarts[x])):
match+=1
has_pains.append(m)
ss.append(c)
else:
no_match+=1
c+=1
for m in suppl:
for x in range(len(pains_smarts)):
if m.HasSubstructMatch(Chem.MolFromSmarts(pains_smarts[x])):
pname.append(pains_name[x])
for m in suppl:
for x in range(len(pains_smarts)):
if m.HasSubstructMatch(Chem.MolFromSmarts(pains_smarts[x])):
psmarts.append(pains_smarts[x])
uniquess = set(ss)
w = Chem.SDWriter('pains_structures.sdf')
notpains = Chem.SDWriter('no_pains_structures.sdf')
temp = 0
for m in suppl:
if temp in uniquess:
w.write(m)
else:
notpains.write(m)
temp += 1
w.flush()
notpains.flush()
import csv
csv_out = open("pains_compounds.csv", "w")
mywriter = csv.writer(csv_out)
for row in zip(ss, psmarts, pname):
mywriter.writerow(row)
csv_out.close()
new_suppl = Chem.SDMolSupplier("pains_structures.sdf")
ms = [x for x in new_suppl if x is not None]
for m in ms: tmp = AllChem.Compute2DCoords(m)
from rdkit.Chem import Draw
img = Draw.MolsToGridImage(ms, molsPerRow = 6, subImgSize = (200, 200), legends = [x.GetProp("ID") for x in ms])
img.save("pains_img.png")
Take a look at the PyQt signaling functionality. For a QPushButton in particular it becomes:
buttonName.clicked.connect(functionName)
Whenever a button is clicked, it will emit the signal clicked which now has functionName registered to execute. n.b. you do not put parentheses after the functionName as you do not want the function to execute, but rather pass the function itself. Additionally the function needs to satisfy the output of the clicked signal, which emits a boolean (so functionName needs to take in that argument). In your case, since you want to pass another object, you can make a method:
def clickHandler(self,checked):
#call function with object to pass as argument here
which calls your method and takes in the object you want to pass
I'm new in PyQt4.
I have a QListWidget, and then i would like to saveit directly but the only example i find is a a textedit and need to open a file first.
But in my case there is no file to open.
is it possible to do it?
so far my code looks like this:
def initUI(self):
self.edit = QtGui.QListWidget()
btn1 = QtGui.QPushButton("Check")
btn2 = QtGui.QPushButton("Quit")
btn1.clicked.connect(self.buttonClicked)
btn2.clicked.connect(self.closeEvent)
toolBar = QtGui.QToolBar()
fileButton = QtGui.QToolButton()
fileButton.setText('File')
fileButton.setMenu(self.menu())
saveButton = QtGui.QToolButton()
saveButton .setText('save')
saveButton .clicked.connect(self.save_menu)
toolBar.addWidget(fileButton)
toolBar.addWidget(saveButton )
def save_menu(self):
fn = QtGui.QFileDialog.getSaveFileName(self, "Save as...", '.',
"ODF files (*.odt);;HTML-Files (*.htm *.html);;All Files (*)")
self.setCurrentFileName(fn)
return self.fileSave()
Assuming you just want to save the text entries in your list, this should work. Beware that it will try and write a file to your disk.
import sys
import os
from PyQt4 import QtGui
class AnExample(QtGui.QMainWindow):
def __init__(self):
super(AnExample, self).__init__()
self.buildUi()
def buildUi(self):
self.listWidget = QtGui.QListWidget()
self.listWidget.addItems(['one',
'two',
'three'])
warning = QtGui.QLabel("Warning, this progam can write to disk!")
saveButton = QtGui.QPushButton('Save to location...')
justSaveButton = QtGui.QPushButton('Just save!')
saveButton.clicked.connect(self.onSave)
justSaveButton.clicked.connect(self.onJustSave)
grid = QtGui.QGridLayout()
grid.addWidget(warning, 0, 0)
grid.addWidget(self.listWidget, 1, 0)
grid.addWidget(saveButton, 2, 0)
grid.addWidget(justSaveButton, 3, 0)
central = QtGui.QWidget()
central.setLayout(grid)
self.setCentralWidget(central)
def onSave(self):
self.saveFile(True)
def onJustSave(self):
self.saveFile(False)
def saveFile(self, showDialog):
"""
Function that will save list items to file.
"""
# save to TESTING.txt in current working directory
savePath = os.path.join(os.getcwd(),
'TESTING.txt')
# allow user to override location if requested
if showDialog:
savePath = QtGui.QFileDialog.getSaveFileName(self,
'Save text file',
savePath,
'TESTING.txt')
# if just saving, or user didn't cancel, make and save file
if len(savePath) > 0:
with open(savePath, 'w') as theFile:
for i in xrange(self.listWidget.count()):
theFile.write(''.join([str(self.listWidget.item(i).text()),
'\n']))
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
ex = AnExample()
ex.show()
sys.exit(app.exec_())