I write openweathermap site appindicator in python, but i need only text label in indicator without icon. But when i leave "" then show me empty icon. Why, i need only text. In Ubuntu 12.04 python-appindicator don't need a icon if leave "" then not load a empty icon, but in ubuntu 14.04 leave empty icon. How to disable the icon?? Any ideas?
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys
import urllib2
import json
import time
import datetime
from gi.repository import Gtk, Gdk, GLib, GObject
from gi.repository import AppIndicator3 as appindicator
class programa:
def __init__(self):
# Create Indicator with icon and label
# If leave empty "" then load empty icon
self.ind = appindicator.Indicator.new("Weather","",appindicator.IndicatorCategory.APPLICATION_STATUS)
self.ind.set_status(appindicator.IndicatorStatus.ACTIVE) #
self.menu_structure()
# Menu structure
def menu_structure(self):
refresh = 720 # Refresh interval in seconds
url = urllib2.Request('http://api.openweathermap.org/data/2.5/weather?q=siauliai&units=metric')
openup = urllib2.urlopen(url) # open url
json_string = openup.read() #read data
parsed_json = json.loads(json_string)
# Get data
temp = parsed_json['main']['temp'] # Temperature in metric system
wind = parsed_json['wind']['speed'] # Wind speed
humidity = parsed_json['main']['humidity']
clouds = parsed_json['clouds']['all']
weather = parsed_json['weather'][0]['main']
weather_desc = parsed_json['weather'][0]['description']
update_time = parsed_json['dt']
updated = datetime.datetime.fromtimestamp(int(update_time)).strftime('%H:%M')
# GTK menu
self.menu = Gtk.Menu()
self.menu_updated = Gtk.MenuItem("Updatet: "+updated)
self.menu_weather = Gtk.MenuItem("Weather: "+weather)
self.menu_desc = Gtk.MenuItem("Desc: "+weather_desc)
self.menu_clouds = Gtk.MenuItem("Clouds: "+str(clouds)+"%")
self.menu_humidity = Gtk.MenuItem("Humidity: "+str(humidity)+"%")
self.menu_wind = Gtk.MenuItem("Wind: "+str(wind)+" m/s")
self.separator = Gtk.SeparatorMenuItem()
self.exit = Gtk.MenuItem("Exit")
self.exit.connect("activate", self.quit)
#show menu
self.menu_updated.show()
self.menu_weather.show()
self.menu_desc.show()
self.menu_clouds.show()
self.menu_humidity.show()
self.menu_wind.show()
self.separator.show()
self.exit.show()
# Append menu
self.menu.append(self.menu_updated)
self.menu.append(self.menu_weather)
self.menu.append(self.menu_desc)
self.menu.append(self.menu_clouds)
self.menu.append(self.menu_humidity)
self.menu.append(self.menu_wind)
self.menu.append(self.separator)
self.menu.append(self.exit)
self.ind.set_menu(self.menu)
# Set label in celcius temperature
self.ind.set_label(str(temp)+u"\u2103".encode('utf-8'),"")
# close url
openup.close()
# Refresh indicator
GLib.timeout_add_seconds(refresh,self.menu_structure)
def quit(self, widget):
sys.exit(0)
if __name__ == "__main__":
indicator = programa()
Gtk.main()
The only way I've found is to either use your own thin invisible icon or to use a thin and subtle existing ubuntu png such as /usr/share/unity/icons/panel-shadow.png or you could implement a little of both:
icon_image = os.path.dirname(__file__) + "/my_thin_inv_icon.png"
if not os.path.isfile(icon_image):
icon_image = "/usr/share/unity/icons/panel-shadow.png"
self.ind = appindicator.Indicator.new("Weather",icon_image,appindicator.IndicatorCategory.APPLICATION_STATUS)
Related
I am a beginner programmer, writing my first application in kivy. And ran into limited storage issue for android - 11 (API 30). How to get the absolute path from the pop-up window when the user selects the folder to save the application data in which I am going to store some data. My application works fine without this choice on 9 anroid, but here's the problem.
here is the minimal code from that window. How to get the absolute path 'root_id' for further manipulations with this folder. By creating files in it and opening SaveDialoga in kivy
from kivy.uix.label import Label
import os
from android import activity, mActivity
from jnius import autoclass
from kivy.app import App
from jnius import cast
from android.storage import app_storage_path, primary_external_storage_path, secondary_external_storage_path
Intent = autoclass('android.content.Intent')
DocumentsContract = autoclass('android.provider.DocumentsContract')
Document = autoclass('android.provider.DocumentsContract$Document')
class Demo(App):
REQUEST_CODE = 42 # unique request ID
def set_intent(self):
intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
mActivity.startActivityForResult(intent, self.REQUEST_CODE)
def intent_callback(self, requestCode, resultCode, intent):
if requestCode == self.REQUEST_CODE:
msg = ""
root_uri = intent.getData()
print(root_uri.getPath())
# /tree/primary:CarInWay
root_id = DocumentsContract.getTreeDocumentId(root_uri)
print( root_id)
# primary:CarInWay
from pathlib import Path
p = Path(root_uri.getPath()).resolve()
print(p, p.is_dir(), p.is_absolute())
# /tree/primary:CarInWay False True
p = Path(root_id).resolve()
print( p, p.is_dir(), p.is_absolute())
# /data/data/car.carinway/files/app/primary:CarInWay False True
primary_ext_storage = primary_external_storage_path()
data_dir = str(os.path.join(primary_ext_storage, 'CarInWay'))
check_data_dir = os.path.exists(data_dir)
print(data_dir , check_data_dir)
# /storage/emulated/0/CarInWay === True
p = Path(primary_ext_storage + '/CarInWay')
print('===', p, '===', p.stat().st_mode)
# /storage/emulated/0/CarInWay === 16832
settings_path = app_storage_path()
secondary_ext_storage = secondary_external_storage_path()
print(settings_path, primary_ext_storage, secondary_ext_storage)
# /data/user/0/car.carinway/files /storage/emulated/0 None
def on_start(self):
self.set_intent()
def build(self):
activity.bind(on_activity_result=self.intent_callback)
self.label = Label()
return self.label
if __name__ == '__main__':
Demo().run()
Sorry for the not quite accurate postal question. But my problem is saving the data in non-application folders, so that when the application is updated, they are not overwritten.
The solution to the problem turned out to be simple.
context = autoclass('android.content.Context')
path_file = context.getExternalFilesDir(None)
path = path_file.getAbsolutePath()
Which made it possible to create a folder in ANDROID / DATA. Where can I already create and store data.
I'm still getting to grips with QT... I've made a python file and a QML file. the Python file updates the gauge's value from data it gets over UDP.
This only works once though... the first UDP packet comes in and updates the gauge, but when it gets the next packet,despite the value updating, the gauge itself does not.
QML
CircularGauge {
id: circularGauge
x: 30
y: 30
value: itt1value
minimumValue: 0
maximumValue: 1200
tickmarksVisible: false
style: CircularGaugeStyle {
maximumValueAngle: 400
minimumValueAngle: 90
}
}
Python:
def configureApplication():
# Set up the application window
app = QGuiApplication(sys.argv)
view = QQuickView()
view.setResizeMode(QQuickView.SizeRootObjectToView)
view.setTitle("my title")
# Load the QML file
qml_file = os.path.join(os.path.dirname(__file__), "maingui.qml")
view.setSource(QUrl.fromLocalFile(os.path.abspath(qml_file)))
# load the slots into the QML file
view.rootContext().setContextProperty("itt1value", 0)
t = threading.Thread(target=receivedata, args=(view,))
t.start()
# Show the window
if view.status() == QQuickView.Error:
sys.exit(-1)
view.show()
# execute and cleanup
app.exec_()
del view
In the threaded method receivedata() I get the data from UDP, process it, then send it to the gauge like so:
view.rootContext().setContextProperty("itt1value", itt)
receivedata() has a while loop in it with the above details, but the gauge only actually updates once. If I put a statement in the QML file to display itt1value, it always has the correct value, so do I need to put in a method to detect the change to this value and re-paint the gauge?
Edit: I was asked for the details of receivedata(), so I have attached it here:
def receivedata(view):
print("Starting UDP server...")
UDP_IP = "192.168.0.14"
UDP_PORT = 49000
sock = socket.socket(socket.AF_INET, # Internet
socket.SOCK_DGRAM) # UDP
sock.bind((UDP_IP, UDP_PORT))
olditt = 0
loopruns = 0 # for debugging
while True:
rawstring = sock.recv(1024)
hexarray = []
#lots of irrelevent formatting here, result is int(value)
itt = float(hextoint(value, olditt))
olditt = itt
itt = format(itt, '.3f')
current = str(loopruns) # for debugging
view.setTitle(current) # for debugging
view.rootContext().setContextProperty("itt1value", itt)
loopruns = loopruns + 1
print(itt)
You have the following errors:
You cannot directly modify the GUI from another thread.
A value can be exported again with setContextProperty(), this will not change the previous value unless the QML is reloaded.
If you want "itt" to modify any value in QML it must be of compatible types, in this case the value of CircularGauge is "real" and therefore the type of data supported in python is float.
Considering the above, I have created a QObject since it can notify changes through signals since it is thread-safe, and export the QObject making connections using Connections.
main.py
import os
import random
import sys
import threading
import time
from PySide2.QtCore import QObject, QUrl, Signal
from PySide2.QtGui import QGuiApplication
from PySide2.QtQuick import QQuickView
class Connections(QObject):
titleChanged = Signal(str, arguments=["title"])
valueChanged = Signal(float, arguments=["value"])
def receivedata(connector):
# configurations
loopruns = 0
while True:
# other stuff
time.sleep(0.1)
itt = random.uniform(0.0, 1200.0)
connector.valueChanged.emit(itt)
connector.titleChanged.emit(str(loopruns))
loopruns += 1
def main(args):
app = QGuiApplication(args)
view = QQuickView(title="my title", resizeMode=QQuickView.SizeRootObjectToView)
connector = Connections()
connector.titleChanged.connect(view.setTitle)
view.rootContext().setContextProperty("connector", connector)
# Load the QML file
qml_file = os.path.join(os.path.dirname(__file__), "maingui.qml")
view.setSource(QUrl.fromLocalFile(os.path.abspath(qml_file)))
# start thread
threading.Thread(target=receivedata, args=(connector,)).start()
# Show the window
if view.status() == QQuickView.Error:
return -1
view.show()
# execute and cleanup
ret = app.exec_()
del view
return ret
if __name__ == "__main__":
sys.exit(main(sys.argv))
maingui.qml
import QtQml 2.13
import QtQuick.Extras 1.4
import QtQuick.Controls.Styles 1.4
CircularGauge {
id: circularGauge
value: 100
minimumValue: 0
maximumValue: 1200
tickmarksVisible: false
style: CircularGaugeStyle {
maximumValueAngle: 400
minimumValueAngle: 90
}
Connections{
target: connector
onValueChanged: circularGauge.value = value
}
}
I was wondering if there is any way to find the name of the last window created in Maya, knowing that I can't add any information to the window itself before that... I checked in both the cmds and API but couldn't find anything. Maybe in PyQt but I don't know much about it.
I'm looking for any solution. Thanks
you can work with something like a close callback, save the needed information and restore it again
def restoreLayout(self):
"""
Restore the layout of each widget
"""
settings=self.settings
try:
self.restoreGeometry(settings.value("geometry").toByteArray())
self.restoreState(settings.value("windowState").toByteArray())
size=settings.value('fontSize').toFloat()[0]
self.setFontSize(size)
except:
pass
def saveLayout(self):
"""
Save the layout of each widget
Save the main window id to your data base
"""
settings=self.settings
settings.setValue("geometry", self.saveGeometry())
settings.setValue("windowState", self.saveState())
settings.setValue("fontSize", app.font().pointSize())
def closeEvent(self, event):
QtGui.QMainWindow.closeEvent(self, event)
self.saveLayout()
a simple case/idea to save tha main win_id and a child button_id:
from functools import partial
import json
def close_ui(*args):
win_id = args[0]
if cmds.window(win_id, exists=True):
cmds.deleteUI(win_id, window=True)
with open('dataBase/ui/uidata.json', 'w') as outfile:
json.dump(args, outfile)
win = {}
win["main_win"] = cmds.window()
cmds.columnLayout()
cmds.text( label='closing it' )
win["btn"] = cmds.button( label='Close')
cmds.button(win["btn"],e=True, command=partial(close_ui, win["main_win"], win["btn"]))
cmds.showWindow(win["main_win"])
Here is what I came up with, it's surely not the "cleanest" solution but it works!
# List all the currently opened windows
uisBefore = cmds.lsUI (wnd = True)
# Execute the function which may or may not create a window
func(*args, **kwargs)
# List all the opened windows again
uisAfter = cmds.lsUI (wnd = True)
# Find all the windows that were opened after executing func()
newUIs = [ui for ui in uisAfter if ui not in uisBefore]
If you create a window with the window command, you'll get back the name of the window you just created:
import maya.cmds as cmds
w = cmds.window()
c= cmds.columnLayout()
def who_am_i(*_):
print "window is", w
b = cmds.button('push', c=who_am_i)
cmds.showWindow(w)
If for some reason you don't own the code that creates the window:
existing_windows = set(cmds.lsUI(type = 'window'))
// make your window here
new_windows = list(set(cmds.lsUI(type = 'window') - existing_windows))
When I run my script, the main form pops-up maximized (i.e. taking all the space on my screen). I tried to set the height and width of the form using the CSS file but it did not work. I haven't seen anything about it elsewhere.
Here's my code:
import sys
import pyforms
from pyforms import BaseWidget
from pyforms.Controls import ControlText
from pyforms.Controls import ControlButton
from pyforms.Controls import ControlFile
class ImportIntoFile(BaseWidget):
def __init__(self):
super(ImportIntoFile,self).__init__('HTCondor & EnergyPlus')
self._Input = ControlFile('Input')
self._Output = ControlFile('Output')
self._Import = ControlButton('Import')
self._Close = ControlButton('Close')
self._formset = ['',(' ','_Input',' '),(' ','_Output',' '),('','_Close','','_Import',''),'']
self._Import.value = self.__ImportAction
self._Close.value = self.__CloseAction
def __ImportAction(self):
OutputFile = open(self._Output.value,'a')
InputFile = open(self._Input.value,'r')
OutputFile.close
InputFile.close
def __CloseAction(self):
sys.exit()
if __name__ == "__main__": pyforms.startApp( ImportIntoFile )`
You can pass a window geometry to the pyforms.start_app() call. So something like the code below should work.
if __name__ == "__main__":
pyforms.start_app( ImportIntoFile, geometry=(200, 200, 400, 400) )
I had the same problem. Pyforms uses Qt, so some of these modules will be familiar, and this css will modify them.
I used:
QMainWindow{
max-width:500px;
max-height:500px;
}
to successfully set the size of the main window, but you can't increase the size later, so if all you want is a fixed size window, it works.
I can't find a good solution too. For temporary workaround when I want to avoid maximized by default, what I did is modifying C:\Python27\Lib\site-packages\pyforms\gui\standaloneManager.py.
From
if geometry is not None:
w.show()
w.setGeometry(*geometry)
else:
w.showMaximized()
To
if geometry is not None:
w.show()
w.setGeometry(*geometry)
else:
w.showNormal()
I want to implement a feature which will allow user to navigate in Gtk.TreeView widget by arrow keys, unfortunately select_iter() method is not doing what I was expecting from it, i. e. it fails to select parent node of selected node :P
And now I need explanation why it's not working or hint on some kind of workaround of this issue.
Below is ready to run test program which demonstrates this problem. Problematic line of code is tagged with #FIXME.
from gi.repository import Gtk
from gi.repository import Gdk
class WizardManager(Gtk.Dialog):
'''Dialog window which makes possible to choose type of resource to create by editor.'''
def __init__(self, parent):
super().__init__('Wizard manager', parent, Gtk.DialogFlags.MODAL | Gtk.DialogFlags.DESTROY_WITH_PARENT)
self.set_default_response(Gtk.ResponseType.OK)
self.set_decorated(False)
self.set_size_request(640, 480)
vbox = self.get_content_area()
self.__tree_store = Gtk.TreeStore(str)
self.__tree_view = Gtk.TreeView(self.__tree_store)
self.__tree_view.get_selection().set_mode(Gtk.SelectionMode.SINGLE)
self.__tree_view.connect('key-press-event', self.__on_tree_view_key_press)
self.__tree_view.set_headers_visible(False)
text_renderer = Gtk.CellRendererText()
text_column1 = Gtk.TreeViewColumn(None, text_renderer)
text_column1.add_attribute(text_renderer, 'text', 0)
self.__tree_view.append_column(text_column1)
scrolled_window = Gtk.ScrolledWindow()
scrolled_window.add(self.__tree_view)
vbox.pack_start(scrolled_window, True, True, 0)
self.__populate_tree_store()
self.show_all()
def __on_tree_view_key_press(self, tree_view, event):
# TODO Implement tree navigation with arrow keys
tree_selection = tree_view.get_selection()
selected_iter = tree_selection.get_selected()[1]
if selected_iter:
selected_tree_path = self.__tree_store.get_path(selected_iter)
# Right arrow and Return should expand selected node.
if event.keyval == Gdk.KEY_Right or event.keyval == Gdk.KEY_Return:
tree_view.expand_row(selected_tree_path, False)
# Left arrow should collapse node or select it parent.
elif event.keyval == Gdk.KEY_Left:
if not tree_view.collapse_row(selected_tree_path):
# Unable to collapse node it must be empty. select it's parent.
parent_iter = selected_iter.copy()
if self.__tree_store.iter_parent(parent_iter):
# FIXME Why select_iter() executes without error and is not able to select parent node?
# same goes for select_path() :P
tree_selection.select_iter(parent_iter)
def __populate_tree_store(self):
# Ordinary resources
self.__tree_store.append(None, ('File',))
self.__tree_store.append(None, ('Directory',))
# Python files
python_dir = self.__tree_store.append(None, ('Python',))
self.__tree_store.append(python_dir, ('Python module',))
self.__tree_store.append(python_dir, ('Python package',))
# Django files
django_dir = self.__tree_store.append(python_dir, ('Django',))
self.__tree_store.append(django_dir, ('Django project',))
self.__tree_store.append(django_dir, ('Django app',))
if __name__ == '__main__':
app = Gtk.Window(Gtk.WindowType.TOPLEVEL)
app.connect('destroy', lambda a: Gtk.main_quit())
dlg = WizardManager(app)
dlg.run()
dlg.destroy()
Gtk.main()
Here you have a hint!
#! /usr/bin/python
###########################################################
#
# Basic Gtk.TreeView Example with two sortable columns
#
###########################################################
# use the new PyGObject binding
from gi.repository import Gtk
import os
import getpass # this is only to automatically print your home folder.
class MyWindow(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, title='My Window Title')
self.connect('delete-event', Gtk.main_quit)
# Gtk.ListStore will hold data for the TreeView
# Only the first two columns will be displayed
# The third one is for sorting file sizes as numbers
store = Gtk.ListStore(str, str, long)
# Get the data - see below
self.populate_store(store)
treeview = Gtk.TreeView(model=store)
# The first TreeView column displays the data from
# the first ListStore column (text=0), which contains
# file names
renderer_1 = Gtk.CellRendererText()
column_1 = Gtk.TreeViewColumn('File Name', renderer_1, text=0)
# Calling set_sort_column_id makes the treeViewColumn sortable
# by clicking on its header. The column is sorted by
# the ListStore column index passed to it
# (in this case 0 - the first ListStore column)
column_1.set_sort_column_id(0)
treeview.append_column(column_1)
# xalign=1 right-aligns the file sizes in the second column
renderer_2 = Gtk.CellRendererText(xalign=1)
# text=1 pulls the data from the second ListStore column
# which contains filesizes in bytes formatted as strings
# with thousand separators
column_2 = Gtk.TreeViewColumn('Size in bytes', renderer_2, text=1)
# Mak the Treeview column sortable by the third ListStore column
# which contains the actual file sizes
column_2.set_sort_column_id(1)
treeview.append_column(column_2)
# Use ScrolledWindow to make the TreeView scrollable
# Otherwise the TreeView would expand to show all items
# Only allow vertical scrollbar
scrolled_window = Gtk.ScrolledWindow()
scrolled_window.set_policy(
Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC)
scrolled_window.add(treeview)
scrolled_window.set_min_content_height(200)
self.add(scrolled_window)
self.show_all()
def populate_store(self, store):
directory = '/home/'+getpass.getuser()
for filename in os.listdir(directory):
size = os.path.getsize(os.path.join(directory, filename))
# the second element is displayed in the second TreeView column
# but that column is sorted by the third element
# so the file sizes are sorted as numbers, not as strings
store.append([filename, '{0:,}'.format(size), size])
# The main part:
win = MyWindow()
Gtk.main()