Add filebrowser in Kivy - python

I have a simple working code which display 2 images, however i want it to display after the file has been browsed.
My code:
from kivy.uix.image import Image
from kivy.uix.floatlayout import FloatLayout
from kivy.app import App
from kivy.uix.scatter import Scatter
class CanvasApp(App):
def build(self):
f = floatlayout()
s = Scatter()
s1 = Scatter()
img_1 = Image(source='img0.jpg',pos=(10,280), size=(300,300))
img_2 = Image(source='img1.jpg',pos=(350,280), size=(300,300))
f.add_widget(s)
s.add_widget(img_1)
f.add_widget(s1)
f.add_widget(img_2)
return f
if __name__ == '_main__':
CanvasApp().run()
Issues in above code:
1. How to provide path in source using filebrowser, what i know about file browser,
from os.path import sep, expanduser, isdir, dirname
user_path = expanduser('~') + sep + 'Documents'
browser = FileBrowser(select_string='Select',
favorites=[(user_path, 'Documents')])
How can i use scatter independently for both images. In above mentioned method i can only use scatter properties on img0.jpg

In the original kivy.garden.Filebrowser example the following two imports are not mentioned:
from kivy.garden.filebrowser import FileBrowser
from kivy.utils import platform
Here is a small working example:
from kivy.app import App
from os.path import sep, expanduser, isdir, dirname
from kivy.garden.filebrowser import FileBrowser
from kivy.utils import platform
class TestApp(App):
def build(self):
if platform == 'win':
user_path = dirname(expanduser('~')) + sep + 'Documents'
else:
user_path = expanduser('~') + sep + 'Documents'
browser = FileBrowser(select_string='Select',
favorites=[(user_path, 'Documents')])
browser.bind(
on_success=self._fbrowser_success,
on_canceled=self._fbrowser_canceled)
return browser
def _fbrowser_canceled(self, instance):
print ('cancelled, Close self.')
def _fbrowser_success(self, instance):
print (instance.selection)
TestApp().run()

Related

Pytube/Pytube3 not working with kivy after installed on Android device [Compiled with Buildozer]

I am trying to make an app that downloads YouTube videos for my first project with kivy. The program works just fine on windows 10, however, it doesn't operate on Android. I believe my problem has come down to whether or not I am using the correct pytube library (whether that be "pytube" or "pytube3"). Also, would anyone know how to correctly set up the buildozer.spec file for the specified imports?
P.S. How would I include the DownloadedVideos folder into the buildozer.spec?
This is a test model BTW, so code improvements to come ;)
from pytube import YouTube
import pytube
import os
import kivy
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivy.uix.gridlayout import GridLayout
from kivy.uix.textinput import TextInput
from kivy.uix.checkbox import CheckBox
import certifi
import os
# Here's all the magic !
os.environ['SSL_CERT_FILE'] = certifi.where()
class MyGrid(GridLayout):
def __init__(self, **kwargs):
super(MyGrid, self).__init__(**kwargs)
self.cols = 1
self.add_widget(Label(text="Paste your YouTube link into the first box on the right. \nOnce you have done so,"
" hit the submit button. \nThe submit button will allow the app to search for the"
" video and confirm its existence. \nThen, a download button with options"
" will appear. \nSelect the options you wish to have downloaded (keeping in mind"
" that audio files need 'kbps' and '.mp3'), and they will be downloaded.",
halign="left", valign="top", font_size=12))
self.inside = GridLayout()
self.inside.cols = 2
self.inside.add_widget(Label(text="Paste YouTube Link:"))
self.link = TextInput(multiline=False)
self.inside.add_widget(self.link)
self.button1 = Button(text="Submit", on_press=self.callback)
self.button1.bind(on_press=self.callback)
self.inside.add_widget(self.button1)
self.outText = TextInput(multiline=True, readonly=True)
self.inside.add_widget(self.outText)
self.inside.add_widget(Label(text="Media:"))
self.ytTypes = TextInput(multiline=True, readonly=True)
self.inside.add_widget(self.ytTypes)
self.add_widget(self.inside)
def downloadMedia(self, instance):
global stream
print(f"Downloading... {stream}")
self.ytTypes.text = f"Downloading... {stream}"
out_file = stream.download("DownloadedVideos")
print(f"Downloaded {stream}")
global yt
self.ytTypes.text = f"Downloaded \n{yt.title}!"
try:
print("here")
self.remove_widget(self.download)
except:
print("Error")
def callback(self, instance):
youtubeLink = self.link.text
print("pressed", youtubeLink)
try:
global yt
yt = YouTube(youtubeLink)
print("Views: ", yt.title)
print("Length: ", yt.length)
print("Views", yt.views)
#Rounds the length of the YouTube video in minutes down to 2 decimal places
res = "{:.2f}".format(yt.length/60)
self.outText.text = f"Title: {yt.title}, \nLength: {res} minutes, \nViews: {yt.views}"
#Grabs video itags and displays them
global stream
stream = yt.streams.filter(progressive=True).last()
print(stream)
print("pass")
print(stream.itag)
self.ytTypes.text = f"Streams: {stream}"
self.download = Button(text="Download:")
self.download.bind(on_press=self.downloadMedia)
self.add_widget(self.download)
except:
print("error")
self.outText.text = "ERR"
self.link.text = ""
class MyApp(App):
def build(self):
return MyGrid()
if __name__ == "__main__":
MyApp().run()

Run Flask app in Kivy app when a button is pressed

Is there a way that I could run Kivy and Flask at the same time in a Kivy app? Furthermore, I need the app so once you click a button in the Kivy app, that triggers a function where a Flask web page is started. Then, using the Python builtin webbrowser module, I need it to automatically open the web page in the default browser.
When this code is ran, I get no error. Just the Kivy app freezes and does not respond anymore.
My code so far:
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
from flask import Flask
from werkzeug.serving import run_simple
import webbrowser
Builder.load_file('design.kv')
answers = []
class CalcScreen(Screen):
def list_view(self):
self.manager.current = "list_screen"
def cround_view(self):
self.manager.current = "round_calc_screen"
def calculate(self):
LengthVal = float(self.ids.length.text)
WidthVal = float(self.ids.width.text)
ThicknessVal = float(self.ids.thickness.text)
FinalCalc = LengthVal * WidthVal * ThicknessVal / 144
FinalCalc = round(FinalCalc,1)
answers.append(FinalCalc)
self.ids.board_feet.text = str(FinalCalc)
class ListScreen(Screen):
def calc_view(self):
self.manager.current = "calc_screen"
def UpdateInfo(self):
tot = 0
for num in answers:
tot += num
self.ids.total_board_feet.text = str(round(tot,1))
self.ids.total_boards.text = str(len(answers))
self.ids.list.text = str(', '.join(map(str, answers)))
def ClearListAnswers(self):
answers.clear()
def printerview(self):
app = Flask(__name__)
#app.route('/')
def home():
return f"<h1>BFCalc Printer Friendly View</h1>\n{self.ids.list.text}"
run_simple('localhost',5000,app)
webbrowser.open_new('localhost:5000')
class RoundCalcScreen(Screen):
def calc_view(self):
self.manager.current = "calc_screen"
def rc_calculate(self):
RC_DiameterVal = float(self.ids.rc_diameter.text)
RC_RadiusVal = RC_DiameterVal / 2
RC_ThicknessVal = float(self.ids.rc_thickness.text)
RC_FinalCalc = (3.14 * (RC_RadiusVal * RC_RadiusVal) * RC_ThicknessVal) / 144
RC_FinalCalc = round(RC_FinalCalc,1)
answers.append(RC_FinalCalc)
self.ids.rc_board_feet.text = str(RC_FinalCalc)
class RootWidget(ScreenManager):
pass
class MainApp(App):
def build(self):
self.icon = 'icon.ico'
return RootWidget()
if __name__ == "__main__":
MainApp().run()
It is a bad practice to use backend frameworks in that way (they are not used that way at all). It depends on your needs, you can try to use pure HTML instead.
def printerview(self):
import webbrowser
file_name = "my_html.html"
html = f"""<h1>BFCalc Printer Friendly View</h1>\n{self.ids.list.text}"""
with open(file_name, "w+") as f:
f.write(html)
# open html in a browser
webbrowser.open(file_name)

Converting multiple HTML files to PDF using PyQt5

I tried following this answer: How to use PyQT5 to convert multiple HTML docs to PDF in one loop
I modified it to convert all html files found in a local folder. For example htmls is a list of html files to be converted: [Q:\Ray\test1.html, Q:\Ray\prac2.html]
This is the code. However, when I try to run it, Python just freezes and I have to stop the run.
import os
import glob
from PyQt5 import QtWidgets, QtWebEngineWidgets
class PdfPage(QtWebEngineWidgets.QWebEnginePage):
def __init__(self):
super().__init__()
self._htmls = []
self._current_path = ""
self.setZoomFactor(1)
self.loadFinished.connect(self._handleLoadFinished)
self.pdfPrintingFinished.connect(self._handlePrintingFinished)
def convert(self, htmls):
self._htmls = iter(zip(htmls))
self._fetchNext()
def _fetchNext(self):
try:
self._current_path = next(self._htmls)
except StopIteration:
return False
def _handleLoadFinished(self, ok):
if ok:
self.printToPdf(self._current_path)
def _handlePrintingFinished(self, filePath, success):
print("finished:", filePath, success)
if not self._fetchNext():
QtWidgets.QApplication.quit()
if __name__ == "__main__":
current_dir = os.path.dirname(os.path.realpath(__file__))
folder= current_dir+ '\\*.HTML'
htmls= glob.glob(folder)
app = QtWidgets.QApplication([])
page = PdfPage()
page.convert(htmls)
app.exec_()
print("finished")
It seems that the OP has not understood the logic of my previous solution which is:
Get the resource, in this case files,
Load it on the page,
When the load is finished then print the content of the page,
When the printing is finished then execute step 1 with the next resource.
In this it does not perform step 2, on the other hand it is recommended that the path of the pdf has a name other than the html
import os
import glob
from PyQt5.QtCore import QUrl
from PyQt5 import QtWidgets, QtWebEngineWidgets
class PdfPage(QtWebEngineWidgets.QWebEnginePage):
def __init__(self):
super().__init__()
self._htmls = []
self._current_path = ""
self.setZoomFactor(1)
self.loadFinished.connect(self._handleLoadFinished)
self.pdfPrintingFinished.connect(self._handlePrintingFinished)
def convert(self, htmls):
self._htmls = iter(htmls)
self._fetchNext()
def _fetchNext(self):
try:
self._current_path = next(self._htmls)
except StopIteration:
return False
else:
self.load(QUrl.fromLocalFile(self._current_path))
return True
def _handleLoadFinished(self, ok):
if ok:
self.printToPdf(self._current_path + ".pdf")
def _handlePrintingFinished(self, filePath, success):
print("finished:", filePath, success)
if not self._fetchNext():
QtWidgets.QApplication.quit()
if __name__ == "__main__":
current_dir = os.path.dirname(os.path.realpath(__file__))
folder= current_dir+ '\\*.HTML'
htmls = glob.glob(folder)
print(htmls)
if htmls:
app = QtWidgets.QApplication([])
page = PdfPage()
page.convert(htmls)
app.exec_()
print("finished")

kivy - button executing function

I'm using Kivy example code to get file path from two different files.
My goal is to use the file path to open and manipulate data from the file.
My problem is to pass the file path into the open file command in the test function below.
Here is my Code:
from kivy.app import App
from kivy.uix.button import Button
from kivy.core.window import Window
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.label import Label
import re
import pandas as pd
class DropFile(Button):
def __init__(self, **kwargs):
super(DropFile, self).__init__(**kwargs)
# get app instance to add function from widget
app = App.get_running_app()
# add function to the list
app.drops.append(self.on_dropfile)
def on_dropfile(self, widget, path):
# a function catching a dropped file
# if it's dropped in the widget's area
if self.collide_point(*Window.mouse_pos):
self.text = path
def test(self):
minimum_wage = open(**FILE PATH HERE**)
LinesToString = ''
for line in minimum_wage:
LinesToString += line
patFinder = re.compile('\d{5}\s+\d{5,9}')
findPat = re.findall(patFinder, LinesToString)
empno_list = []
pattern = '(\d{5})\s+(\d{5})'
for string in findPat:
match = re.search(pattern, string)
empno = match.group(2)
empno_list.append(empno)
MinimumWage = pd.DataFrame({'EMPNO': empno_list})
MinimumWage.set_index('EMPNO')
print MinimumWage.head()
print MinimumWage.shape
class DropApp(App):
def build(self):
# set an empty list that will be later populated
# with functions from widgets themselves
self.drops = []
# bind handling function to 'on_dropfile'
Window.bind(on_dropfile=self.handledrops)
box = BoxLayout(orientation='vertical')
top_label = Label(text='Data manipulation', font_size=45)
box.add_widget(top_label)
run_button = Button(text='Run', size_hint=(1, 0.5))
run_button.bind(on_press=DropFile.test)
box.add_widget(run_button)
two_buttons = BoxLayout(orientation='horizontal')
dropleft = DropFile(text='Drag & Drop File here')
# dropright = DropFile(text='right')
two_buttons.add_widget(dropleft)
# two_buttons.add_widget(dropright)
box.add_widget(two_buttons)
return box
def handledrops(self, *args):
# this will execute each function from list with arguments from
# Window.on_dropfile
#
# make sure `Window.on_dropfile` works on your system first,
# otherwise the example won't work at all
for func in self.drops:
func(*args)
DropApp().run()
Thanks
You can call test() method at the last line of on_dropfile() e.g.:
def on_dropfile(self, widget, path):
# a function catching a dropped file
# if it's dropped in the widget's area
if self.collide_point(*Window.mouse_pos):
self.text = path
self.test(path)
def test(self, path):
minimum_wage = open(path)
LinesToString = ''
...
or launch already from the existing thing e.g. if you run test() separately from the on_dropfile() function and you won't change self.text property after changing the text:
def on_dropfile(self, widget, path):
# a function catching a dropped file
# if it's dropped in the widget's area
if self.collide_point(*Window.mouse_pos):
self.text = path # path is assigned to self.text <--
def test(self):
minimum_wage = open(self.text) # <-- and you can use it
LinesToString = ''
...
Or at the end of on_dropfile put it into a separate variable and use that in open().

Why does QFileSystemWatcher work for directories but not files in Python?

I borrowed this code from another StackOverflow answer:
from PyQt4 import QtCore
#QtCore.pyqtSlot(str)
def directory_changed(path):
print('Directory Changed!!!')
#QtCore.pyqtSlot(str)
def file_changed(path):
print('File Changed!!!')
fs_watcher = QtCore.QFileSystemWatcher(['/path/to/files_1', '/path/to/files_2', '/path/to/files_3'])
fs_watcher.connect(fs_watcher, QtCore.SIGNAL('directoryChanged(QString)'), directory_changed)
fs_watcher.connect(fs_watcher, QtCore.SIGNAL('fileChanged(QString)'), file_changed)
The problem is, file_changed never gets called, no matter what. directory_changed is reliably called when a file is added, for example, but changing the files content does not result in file_changed being called.
I called a few variations of QtCore.SIGNAL('fileChanged(QString)'), eg, QtCore.SIGNAL('fileChanged(const QString &)'), to no avail. There are no warnings, or errors -- it simply does not trigger the function.
Recommendations?
It's hard to be certain what's going wrong, because the example code is incomplete, and so cannot work at all as it stands.
However, assuming the real code you are running is more or less sane/complete, your problem is probably caused by not adding the directory itself to the list of paths.
A basic script should look something like this:
import sys
from PyQt4 import QtCore
def directory_changed(path):
print('Directory Changed: %s' % path)
def file_changed(path):
print('File Changed: %s' % path)
app = QtCore.QCoreApplication(sys.argv)
paths = [
'/path/to',
'/path/to/files_1',
'/path/to/files_2',
'/path/to/files_3',
]
fs_watcher = QtCore.QFileSystemWatcher(paths)
fs_watcher.directoryChanged.connect(directory_changed)
fs_watcher.fileChanged.connect(file_changed)
sys.exit(app.exec_())
import argparse
import configparser
import os
import sys
from PyQt5 import QtCore
from PyQt5.QtGui import QIcon
from PyQt5.QtWidgets import QApplication, QDesktopWidget, QMessageBox
from PyQt5.QtWidgets import QMainWindow
from ProgressBar_ui import Ui_Form
class ProgressBarWindow(QMainWindow, Ui_Form):
def __init__(self):
super().__init__()
self.ui = Ui_Form()
self.ui.setupUi(self)
self.ui.progressBar.setMinimum(0)
self.ui.progressBar.setMaximum(0)
self.ui.progressBar.setValue(0)
self.setWindowTitle("Progress Bar")
self.MSversion = ""
self.LOADING_LOG_PATH = ""
mainIco = ("Icons\myIcon.ico")
self.setWindowIcon(QIcon(mainIco))
self.ui.label.setText("")
self.ui.label.setWordWrap(True)
def location_on_the_screen(self):
ag = QDesktopWidget().availableGeometry()
sg = QDesktopWidget().screenGeometry()
widget = self.geometry()
x = ag.width() - widget.width()
y = 2 * ag.height() - sg.height() - widget.height()
self.move(x, y)
def file_changed(self, pathPassed):
if os.path.exists(pathPassed):
f = open(pathPassed, "r")
for x in f:
#print(x)
label =x
self.ui.label.setText(label)
if x == "CloseLoading":
self.close()
def main():
app = QApplication(sys.argv)
w = ProgressBarWindow()
w.setWindowFlags(w.windowFlags() & ~QtCore.Qt.WindowMaximizeButtonHint)
parser = argparse.ArgumentParser()
parser = argparse.ArgumentParser(description='ProgressBar Arguments')
parser.add_argument('version', action="store", type=str)
args = vars(parser.parse_args())
if len(sys.argv) < 1:
msg = QMessageBox()
msg.setIcon(QMessageBox.Critical)
errorMsg = "There are less than 2 command line arguments provided.\nLauncher can not be run."
msg.setText(errorMsg)
msg.setWindowTitle("Save paths..")
msg.exec_()
sys.exit()
p= '/path/toFile/'
paths = [ p ]
fs_watcher = QtCore.QFileSystemWatcher(paths)
#fs_watcher.directoryChanged.connect(w.directory_changed)
fs_watcher.fileChanged.connect(w.file_changed)
w.location_on_the_screen()
w.show()
app.exec_()
if __name__ == "__main__":
sys.exit(main())

Categories

Resources