Pulling QGIS plugin logic into stand alone Application - python

I'm new to QT, Python, and QGIS. I installed the "Plugin Builder" plugin and generated a Dockwidget. I am able to change the widget using qtcreator and am learning how to implement the signals and slots to work with my own plugin.
Now, to my question. Is there and easy way I can remove the QGIS iface and use my plugin's logic outside of QGIS? I'm not actually using any of the PyQGIS libraries at the moment, but I want to keep my QT interface and Python code/structure generated by the "Plugin Builder". Is there a way to do that?
Thanks.

Yes, there is a way to do it. But so far what I have found is that we need to copy entire Qgis library to the final software package. It is very important to set the correct path for qgis application inside the code as follows:
QgsApplication.setPrefixPath(r"C:\OSGeo4W\apps\qgis", True)
QgsApplication.initQgis()
QgsProject.instance().setFileName(strProjectName)
Also we need to write the file and close it at the end
QgsProject.instance().write()
QgsApplication.exitQgis()
Here's snapshot of the stand alone package I have created. The code needs some modification for some variables to work.
from PyQt4.QtCore import *
from PyQt4.QtGui import *
from qgis.core import *
from qgis.gui import *
import os, datetime
class CreateQgs():
def initQgsFile(self, outputFolder, stopRadius):
strProjectName = str(outputFolder) + "\\" + "PhotoLocationMap.qgs"
QgsApplication.setPrefixPath(r"C:\OSGeo4W\apps\qgis", True)
QgsApplication.initQgis()
QgsProject.instance().setFileName(strProjectName)
highwayShapeFilePath = "C:/Shapefiles/Highway.shp"
arterialShapeFilePath = "C:/Shapefiles/StreetsMajor.shp"
highwayLayer = QgsVectorLayer(self.highwayShapeFilePath, 'HighwayDB' , 'ogr')
arterialLayer = QgsVectorLayer(self.arterialShapeFilePath, 'ArterialDB', 'ogr')
symbols = highwayLayer.rendererV2().symbols()
sym = symbols[0]
sym.setColor(QColor.fromRgb(255,94,94))
highwayLayer.triggerRepaint()
symbols = arterialLayer.rendererV2().symbols()
sym = symbols[0]
sym.setColor(QColor.fromRgb(76,138,245))
arterialLayer.triggerRepaint()
mapInstance = QgsMapLayerRegistry.instance()
mapInstance.instance().addMapLayer(arterialLayer)
mapInstance.instance().addMapLayer(highwayLayer)
QgsProject.instance().write()
QgsApplication.exitQgis()
def unitTest():
app = QgsApplication(sys.argv, True)
photoFolderPath = 'C:\Test\QGis\TestPics'
CreateQgsFile = CreateQgs()
CreateQgsFile.initQgsFile(photoFolderPath, 128)
if __name__ == "__main__":
unitTest()

Related

How to run python from Flutter (Android)

I want to call a python function that uses numpy and pandas from my flutter app and get the output of this function.
I found a way to do that by using ffi package but I don't know how.
some says that I can do this by making a .dylib file from the python project then use this code to call it
final path = absolute('native/libadd.dylib');
final dylib = DynamicLibrary.open(path);
final add = dylib.lookupFunction('add');
but I am getting this error
: Error: Expected type 'NativeFunction<Function>' to be a valid and instantiated subtype of 'NativeType'.
lib/home_screen.dart:32
- 'NativeFunction' is from 'dart:ffi'.
- 'Function' is from 'dart:core'.
final add = dylib.lookupFunction('add');
so I think it's not available on Android
You should try using Flet for this. It is totally writted in Python language and still provide complete flutter functionality and code. Basic app code from it looks something like:
import flet as ft
def main(page: ft.Page):
page.title = "Flet counter example"
page.vertical_alignment = ft.MainAxisAlignment.CENTER
txt_number = ft.TextField(value="0", text_align=ft.TextAlign.RIGHT, width=100)
def minus_click(e):
txt_number.value = str(int(txt_number.value) - 1)
page.update()
def plus_click(e):
txt_number.value = str(int(txt_number.value) + 1)
page.update()
page.add(
ft.Row(
[
ft.IconButton(ft.icons.REMOVE, on_click=minus_click),
txt_number,
ft.IconButton(ft.icons.ADD, on_click=plus_click),
],
alignment=ft.MainAxisAlignment.CENTER,
)
)
ft.app(target=main)
It's just like a numpy or pandas library that you can import right into your project

Python get Desktop Path directly on Windows

Ive seen answers that finds the user's path, and then concatenating it with desktop, Such as:
desktop = os.path.expanduser("~/Desktop")
and
desktop = os.path.join(os.path.join(os.environ['USERPROFILE']), 'Desktop')
However it doesn't work when the device has non-default extensions:
C:\\Users\\NAME\\OneDrive\\Desktop
or non-english extension:
C:\\Users\\NAME\\OneDrive\\桌面
I ended up doing this as an emergency response:
possible_desktop_ext = ['Desktop', 'OneDrive\\Desktop', 'OneDrive\\桌面']
I can definitely see the list expanding exponentially in the future, and I don't really like the feeling of doing this every time I find a new extension.
So what is the most reliable way of retrieving the desktop's path?
This is adapted from https://stackoverflow.com/a/626927/5987, I urge you to go to it and give it the recognition it deserves.
import ctypes
from ctypes import wintypes, windll
CSIDL_DESKTOP = 0
_SHGetFolderPath = windll.shell32.SHGetFolderPathW
_SHGetFolderPath.argtypes = [wintypes.HWND,
ctypes.c_int,
wintypes.HANDLE,
wintypes.DWORD, wintypes.LPCWSTR]
path_buf = ctypes.create_unicode_buffer(wintypes.MAX_PATH)
result = _SHGetFolderPath(0, CSIDL_DESKTOP, 0, 0, path_buf)
print(path_buf.value)

No module named linq Error only when job is using python

I have a table in sql database which I inserted a python code as data.
I wanna map an entity to another one (first one is mine and the second one is from web service). So I used python for mapping. I used this python code in two places and in both of them it just maps the entities. the first place used in Job Service and works Parallel and the Second place is for mapping and show mapped Entity in XML Format.
the problem is when the job is mapping entities, the python says No module named linq!
but when I want to see the mapped entity, it maps and the xml show the mapped entity without any problems. whats wrong? the code is the same but somewhere I get error.
here is some part of my python script. Any opinion?
import System
import clr
import sys
clr.AddReference(''System.Core'')
clr.AddReference(''Tools.Cmn'')
clr.AddReference(''Tools.ThinCmn'')
clr.AddReference(''Common.Cmn'')
clr.AddReference(''Common.SA'')
clr.AddReference(''Life.SA'')
clr.AddReference(''Life.Cmn'')
clr.AddReference(''Life.BL'')
from Tools.Cmn import *
from Common.Cmn import *
from Common.SA import *
from Life.Cmn import *
from Life.BL import *
from Life.SA.CiiRegLifePlcyServices import *
from Life.SA import *
from System import Array
from System import DateTime
from System import Func
from System.Linq import Enumerable
from System.Collections.Generic import *
StrTools = StringToolsExposeToScript()
CIHelper = LifeCIWebServiceHelper()
########################################
def Map(bnVer , lifPlcyReq, extraInfo):
isEdm = 0 if bnVer.ElhNo == 0 else 1
isPrps = extraInfo["IsPrps"]
try :
calcList = bnVer.LifePolicyCalcGeneralList.LoadAll()
for calc in calcList:
clc = System.Activator.CreateInstance(LifPlcyYrReq)
clc.YrNo = calc.Year
clc.PayCnt = calc.InstallmentCnt
clc.Svng = calc.PrmReserved
clc.GrntPrftRte = calc.PolicyYearInterest
clc.CfcChngPrm = calc.PolicyYearPrmChangeZarib
LifPlcyYrLst.Add(clc)
lifPlcyReq.LifPlcyYrLst = LifPlcyYrLst.ToArray()
except TypeError, err:
raise Exception(str(err) + " line : " + str(sys.exc_info()[-1].tb_lineno))
except:
raise
return

how to avoid importing self, intra-package relationships

The directory structure is like so:
AppCenter/
main.pyw
|
|
_apps/
__init__.py
TabularApp.py
UserAdministrationApp.py
RegisterApp.py
FnAdminApp.py
PyUi/
The contents of __init__.py:
import sys
sys.path.insert(1, '.')
__all__ = ['TabularApp',
'UserAdministrationApp',
'RegisterApp',
'FnAdminApp']
The problems pop up:
When main.pyw tries to from _apps import *.
In UserAdministrationApp.py i am trying to dynamically add tooltips to some QListWidget items like so:
for app in self.__APPS__:
app_icon = str(os.path.join(app_icons, f"{app}.png")).replace('\\', '/')
icon = QIcon(app_icon)
if app != self.__class__:
ttip_txt = eval(f'_apps.{app}.__doc__')
else:
ttip_txt = self.__doc__
item = QListWidgetItem(icon, app)
item.setText(app)
item.setToolTip(ttip_txt)
wdg.addItem(item)
The self.__APPS__ is just a copy of _apps.__all__.
The first problem I encountered was that i would get an AttributeError saying module x has no attribute y in ttip_txt = eval(f'_apps.{app}.__doc__') I resolved this by from _apps import * in UserAdministrationApp module. At this point I had already renamed this module for testing purposes and everything worked, but when I changed the name back to UserAdministrationApp.py I got another AttributeError saying module __apps has no attribute UserAdministrationApp.
Questions
I tried reading the python import docs but nothing in it really spoke to me.
I am sensing it has something to do with the script trying to import itself.
But i am still intrigued by these questions:
Why did the import fail in the first case, when i have import _apps?
Why in the second case does it not at least see itself and then produce an ImportError instead of AtributeError?
What is the optimal way to handle these types of situations?
Okay I found a solution, and though i think it is a bit dirty and not in best style, it works.
First
remove the from _apps import * and just from _apps import __all__.
Then
In initialization of the main class from the module UserAdministrationApp import in a loop skipping self.__class_.__name__
self.__APPS__ = _apps.__all__
self.class_name = self.__class__.__name__
for app in self.__APPS__:
if self.class_name != app:
exec(f'import _apps.{app}')
Finally
for app in self.__APPS__:
app_icon = str(os.path.join(app_icons, f"{app}.png")).replace('\\', '/')
icon = QIcon(app_icon)
if app != self.class_name:
ttip_txt = eval(f'_apps.{app}.__doc__')
else:
ttip_txt = self.__doc__
Having found the solution, I would still like to hear why the error was in the first place, for educational purposes.
So if anybody at any time glances over this and knows how to...you are more than welcome.

What can you do with COM/ActiveX in Python? [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 4 years ago.
Improve this question
I've read that it is possible to automate monthly reports in Crystal Reports with COM/ActiveX. I'm not that advanced to understand what this is or what you can even do with it.
I also do a lot of work with Excel and it looks like you also use COM/ActiveX to interface with it.
Can someone explain how this works and maybe provide a brief example?
First you have to install the wonderful pywin32 module.
It provides COM support. You need to run the makepy utility. It is located at C:\...\Python26\Lib\site-packages\win32com\client. On Vista, it must be ran with admin rights.
This utility will show all available COM objects. You can find yours and it will generate a python wrapper for this object.
The wrapper is a python module generated in the C:\...\Python26\Lib\site-packages\win32com\gen_py folder. The module contains the interface of the COM objects. The name of the file is the COM unique id. If you have many files, it is sometimes difficult to find the right one.
After that you just have to call the right interface. It is magical :)
A short example with excel
import win32com.client
xlApp = win32com.client.Dispatch("Excel.Application")
xlApp.Visible=1
workBook = xlApp.Workbooks.Open(r"C:\MyTest.xls")
print str(workBook.ActiveSheet.Cells(i,1))
workBook.ActiveSheet.Cells(1, 1).Value = "hello"
workBook.Close(SaveChanges=0)
xlApp.Quit()
You can basically do the equivalent of late binding. So whatever is exposed through IDispatch is able to be consumed.
Here's some code I wrote this weekend to get an image from a twain device via Windows Image Acquisition 2.0 and put the data into something I can shove in a gtk based UI.
WIA_COM = "WIA.CommonDialog"
WIA_DEVICE_UNSPECIFIED = 0
WIA_INTENT_UNSPECIFIED = 0
WIA_BIAS_MIN_SIZE = 65536
WIA_IMG_FORMAT_PNG = "{B96B3CAF-0728-11D3-9D7B-0000F81EF32E}"
def acquire_image_wia():
wia = win32com.client.Dispatch(WIA_COM)
img = wia.ShowAcquireImage(WIA_DEVICE_UNSPECIFIED,
WIA_INTENT_UNSPECIFIED,
WIA_BIAS_MIN_SIZE,
WIA_IMG_FORMAT_PNG,
False,
True)
fname = str(time.time())
img.SaveFile(fname)
buff = gtk.gdk.pixbuf_new_from_file(fname)
os.remove(fname)
return buff
It's not pretty but it works. I would assert it's equivalent to what you would have to write in VB.
Here is a working solution that creates a file and adds value to a cell:
import win32com.client
import xlsxwriter
import os
cwd = os.getcwd()
file_path = cwd + "\\test.xlsx"
#Create an excel file
workbook = xlsxwriter.Workbook(file_path)
worksheet = workbook.add_worksheet()
workbook.close()
#Open an excel application
xlApp = win32com.client.Dispatch("Excel.Application")
xlApp.Visible=1
workBook = xlApp.Workbooks.Open(file_path)
print str(workBook.ActiveSheet.Cells(1,1))
workBook.ActiveSheet.Cells(1, 1).Value = "hello55"
workBook.Close(SaveChanges=1)
xlApp.Quit()
How to receive ActiveX events in python 3
# coding=utf8
from PyQt5.QAxContainer import *
from PyQt5.QtWidgets import *
from PyQt5.QtCore import QObject
import sys
TITLE = "CallX Python Example: accept any calls"
TrueConfCallX_Class = '{27EF4BA2-4500-4839-B88A-F2F4744FE56A}'
SERVER = '' # empty - connect to TrueConf Online cloud
USER = '<trueconf id>'
PASSWORD = '<password>'
class CallXWindow(QWidget):
def __init__(self):
QAxWidget.__init__(self)
self.setWindowTitle(TITLE)
self.move(400, 30)
# end of class CallXWindow(QWidget)
class ActiveXExtend(QObject):
def __init__(self, view):
super().__init__()
self.view = view
self.ocx = QAxWidget(TrueConfCallX_Class)
self.ocx.move(0, 0)
self.ocx.setFixedSize(640, 375)
self.ocx.setParent(self.view)
self.ocx.show()
# receive some ActiveX events
self.ocx.OnXAfterStart.connect(self._OnXAfterStart)
self.ocx.OnServerConnected[str].connect(self._OnServerConnected)
self.ocx.OnLogin[str].connect(self._OnLogin)
self.ocx.OnInviteReceived[str].connect(self._OnInviteReceived)
self.ocx.OnXError[int, str].connect(self._OnXError)
self.ocx.OnXLoginError[int].connect(self._OnXLoginError)
# Events
def _OnXAfterStart(self):
print("**OnXAfterStart")
# select devices
self.ocx.XSetCameraByIndex(0)
self.ocx.XSelectMicByIndex(0)
self.ocx.XSelectSpeakerByIndex(0)
# connect to server
self.ocx.connectToServer(SERVER)
def _OnServerConnected(self, eventDetails):
print("**OnServerConnected")
print(eventDetails)
# login
self.ocx.login(USER, PASSWORD)
def _OnLogin(self, eventDetails):
print("**OnLogin")
def _OnInviteReceived(self, eventDetails):
print("**OnInviteReceived")
print(eventDetails)
# accept any calls
self.ocx.accept()
def _OnXError(self, errorCode, errorMsg):
print("**OnXError")
print('{}. Code: {}'.format(errorMsg, errorCode))
def _OnXLoginError(self, errorCode):
print("**OnXLoginError")
if errorCode == 8:
print('Support for SDK Applications is not enabled on this server')
else:
print('Login error. Code: {}'.format(errorCode))
# end of class ActiveXExtend(QObject)
if __name__ == '__main__':
app = QApplication(sys.argv)
MainWindow = CallXWindow()
axwin = ActiveXExtend(MainWindow)
MainWindow.show()
sys.exit(app.exec_())

Categories