api: how to get selected text from object sublime.Selection - python

How to get selected text in sublime text 3 plugin:
import sublime, sublime_plugin
class plugin_window__go_to_relative_plugin__Command(sublime_plugin.WindowCommand):
def run(self):
window = self.window
view = window.active_view()
sel = view.sel()
sublime.status_message("selection: "+sel)
My code throws error:
sublime.status_message("selection: "+sel)
TypeError: Can't convert 'Selection' object to str implicitly
view.sel() returns sublime.Selection object. But I don't know how to get selected text from there.
This plugin must work as following:
When I call it on view...
... it should set text "dow = self.w" to variable sel
When I do str(sel) it returns <sublime.Selection object at 0x1047fd8d0>
Docs are not very clear for me.

My understanding of what the documentation means is this:
It sounds like the sel() method of a sublime.View object returns a sublime.Selection object, which is a container of regions—so you should be able to iterate over its contents (the regions it contains) or index into them using the [] operation.
You can get the text associated with each sublime.Region in a Selectionby calling the substr(region) method of a sublime.View object. This makes sense as this editor allows there to be multiple simultaneous selections—one of its cooler features, IMHO.
Hope this helps.

In case of single selection:
import sublime, sublime_plugin
class selection_plugin__Command(sublime_plugin.WindowCommand):
def run(self):
print('selection_plugin__ called')
window = self.window
view = window.active_view()
sel = view.sel()
region1 = sel[0]
selectionText = view.substr(region1)
print(selectionText)

Use it in console and then append in python
view.substr((view.sel())[0])

Related

Python CLR WinForms - Opening another from from an existing form

I am having some extreme difficulty with something so simple. All I am trying to do is launch another Windows Form from an existing Windows Form in Python. I've tried everything I can think of and I cannot figure out. Below is a example program:
import clr
clr.AddReference("System.Windows.Forms")
clr.AddReference("System.Drawing")
clr.AddReference("System.ComponentModel")
from System.Windows.Forms import *
from System.Drawing import *
class MyForm(Form):
def __init__(self):
self.StartPosition = FormStartPosition.CenterScreen
self.btnTest = Button()
self.btnTest.Name = 'btnTest'
self.btnTest.Text = "Test"
self.btnTest.Size = Size(80, 30)
self.Controls.Add(self.btnTest)
self.btnTest.Click += self.Add_Control_Limits_Form_Click
def Add_Control_Limits_Form_Click(self, sender, args):
Application.Run(MySecondForm())
class MySecondForm(Form):
def __init__(self2):
self2.StartPosition = FormStartPosition.CenterScreen
self2.AutoScaleMode = AutoScaleMode.Font
self2.ClientSize = Size(800, 450)
self2.Text = "Form2"
Application.EnableVisualStyles()
Application.SetCompatibleTextRenderingDefault(False)
Application.Run(MyForm())
Which, when I run it, it gives me this error message:
InvalidOperationException : Starting a second message loop on a single thread is not a valid operation. Use Form.ShowDialog instead.
I don't think it's as simple as just putting MySecondForm.ShowDialog() since I have this as a class. What am I missing?
I figured it out.
So, within the button click event, add these lines of code:
self.TopLevel = False
YF = YourForm()
YF.ShowDialog()
self.TopLevel = True
...if you want it modal. I did.
You don't need the Application.Run(MySecondForm()) code within the button click event.
Then, within your second form class, just initialize your form the way you want.

Calling a method with another method within another class (calling Method_B within Class_B, with Method_A within Class_A)

I am a Maya user and I am currently writting an Auto-Rig.
I created different Classes for each major tasks of the tool. (ex: Class_UI, Class_Arms_Rig, etc..)
The problem I have is that I can't call a method from "Class_Joints" (the class that will generates every needed Joints) with my "Class_UI"
Here are the codes :
First the Class_UI
import sys
sys.path.append('G:\\3D2\\Script\\Auto_Rig')
import Class_Joints
import Class_Arms
import maya.cmds as mc
class Window_UI(object):
# Initializing global variables
def __init__(self):
# Getting acces to the different modules
self.Arms = Class_Arms.Arms_Rig()
self.Joints = Class_Joints.Gen_Joints()
# Create Ui
self.create_UI()
# Creating the UI
def create_UI(self):
# Create window
self.UI = mc.window(title='Auto-Rig Tool', w=(300), h=(350))
# Main layout
self.mainLayout = mc.menuBarLayout()
### Joints Option ###
# Create Joints Button
self.createJointsButton = mc.button(label='Create Joints', command=self.Joints.gen_arms_joints)
Window_UI()
mc.showWindow()
Then the Class_Joints :
import maya.cmds as mc
class Gen_Joints:
# Creating arm Jnts and the list of it
def gen_arms_joints(self):
self.shoulderJnt = mc.joint(absolute=True, position=[5,8,0], n='L_Shoulder_Jnt')
self.elbowJnt = mc.joint(absolute=True, position=[10,8,-1.5], n='L_Elbow_Jnt')
self.wristJnt = mc.joint(absolute=True, position=[15,8,0], n='L_Wrist_Jnt')
self.handcupJnt = mc.joint(absolute=True, position=[18,8,0], n='L_HandCup_Jnt')
self.jntList = mc.ls(self.shoulderJnt, self.elbowJnt, self.wristJnt, self.handcupJnt)
When I run the Class_UI Code, the button within the UI is supposed to run the gen_arms_joints method within the Class_Joints
But I get this error message : # Error: gen_arms_joints() takes exactly 1 argument (2 given) #
I know that self is an implicit argument here but I do not know how to avoid this error.
Thank you all for your time.
:D
Cordially, Luca.
Two things i would recommend you do. I dont use Maya but i have built apps with multiple different GUIs.
Every GUI I've used when it comes to buttons is the first argument is a reference to self, and then there is usually 1 or 2 more arguments passed in. Some pass the reference to the button itself while others pass a argument that holds event details. My guess is this is what is happening. When you click the button it is passing in an "event" object that hold details about what was clicked and other details.
To truly find out what is passed change your function signature to this and see what is logged.
def gen_arms_joints(self, mystery_second_arg):
print(type(mystery_second_arg), mystery_second_arg)
self.shoulderJnt = mc.joint(absolute=True, position=[5,8,0], n='L_Shoulder_Jnt')
self.elbowJnt = mc.joint(absolute=True, position=[10,8,-1.5], n='L_Elbow_Jnt')
self.wristJnt = mc.joint(absolute=True, position=[15,8,0], n='L_Wrist_Jnt')
self.handcupJnt = mc.joint(absolute=True, position=[18,8,0], n='L_HandCup_Jnt')
self.jntList = mc.ls(self.shoulderJnt, self.elbowJnt, self.wristJnt, self.handcupJnt)
The issue is that in the __init__() call of the Class_UI, you have defined the wrong class call for the actual function gen_arm_joints(self), it should be: self.Joints = Gen_Joints(), seems like you have different import classNames but in the code you have called the class as Gen_Joints. You can't pass in two self classes references i.e the error traceback.
You will have to fix the import class to import Gen_Joints.
#FishingCode
Look out what I tried based on what you told me :
import sys
sys.path.append('G:\\3D2\\Script\\Auto_Rig')
import Class_Joints
import Class_Arms
import maya.cmds as mc
class Window_UI(object):
# Initializing global variables
def __init__(self):
# Getting acces to the different modules
self.Arms = Class_Arms.Arms_Rig()
self.Joints = Gen_Joints()
# Create Ui
self.create_UI()
# Creating the UI
def create_UI(self):
# Create window
self.UI = mc.window(title='Auto-Rig Tool', w=(300), h=(350))
# Main layout
self.mainLayout = mc.menuBarLayout()
# Create Joints Button
self.createJointsButton = mc.button(label='Create Joints', command=self.Joints.gen_arms_joints)
#show window
Window_UI()
mc.showWindow()
It's exactly what I have on Visual Studio Code
import maya.cmds as mc
class Gen_Joints:
# Creating arm Jnts and the list of it
def gen_arms_joints(self):
self.shoulderJnt = mc.joint(absolute=True, position=[5,8,0], n='L_Shoulder_Jnt')
self.elbowJnt = mc.joint(absolute=True, position=[10,8,-1.5], n='L_Elbow_Jnt')
self.wristJnt = mc.joint(absolute=True, position=[15,8,0], n='L_Wrist_Jnt')
self.handcupJnt = mc.joint(absolute=True, position=[18,8,0], n='L_HandCup_Jnt')
self.jntList = mc.ls(self.shoulderJnt, self.elbowJnt, self.wristJnt, self.handcupJnt)
VS Code tells me Undefined variable 'Gen_Joints'
And within maya I get # Error: NameError: file <maya console> line 16: global name 'Gen_Joints' is not defined #
mc.button passes on an extra boolean value to the method, so since that's not defined in gen_arms_joints it throws that error and says it's the wrong number of arguments.
So simply add an extra parameter and it'll fix it:
def gen_arms_joints(self, extra_param):
Or better yet use *args instead to be a bit more generic:
def gen_arms_joints(self, *args):
It's honestly kind of sneaky because it's not really stated in the documentation, but you can see it being used in the example at the bottom of the page.

How to get a variable from a different class?

I have a class named TerminalPanel which has the following method:
def OnSerialRead(self, event):
"""Handle input from the serial port."""
text = event.data
Now, I want to get the value of text from another method (get_data) in another class (GraphicsPanel).
How do I get this value? I tried marito = TerminalPanel.OnserialRead.text, but I get AttributeError: 'function' object has no attribute 'text'
Update
I have set-up the TerminalPanel class to include the variable text as part of it:
def OnSerialRead(self, event):
"""Handle input from the serial port."""
self.text = event.data
But now when I call it like this: marito = TerminalPanel.text inside my GraphicsPanel class I get the following error:
AttributeError: type object 'TerminalPanel' has no attribute 'text'
What am I doing wrong?
I think the problem is a lack of context and confusion what actually to do. I suppose you try to rework the wxTerminal.py from pyserial. I have to admit this part of pyserial is neither very readable (has been created by wxGlade) nor is it easy to understand (requires understanding of the wxPython event system and spinning off of threads (to keep the GUI responsive when reading on the serial port).
However, according to your problem description, it seems to me you want to do the following:
Get the value of event.text when it arrives and process it further in your GraphicsPanel instance.
You have to possibilities:
1) Bind to the event:
In your GraphicsPanel class:
class GraphicsPanel(wx.Panel):
def __init__(...):
...
self.parent = self.GetParent() # this should result in a wx.Frame instance!
# binding on wx.Frame required, because wx.Panel will not catch the event
self.parent.Bind(EVT_SERIALRX, self.OnSerialRead)
def OnSerialRead(self, event):
text = event.text
...
event.Skip() # important: you have to skip it also in ``TerminalPanel`` if you
# want to bind twice
2) Call the routine in GraphicsPanel instance with event.text as argument.
class TerminalPanel(wx.Panel):
def __init__(...):
...
self._grphpnl = GraphicsPanel(...)
self.Bind(EVT_SERIALRX, self.OnSerialRead)
def OnSerialRead(self, event):
text = event.text
# do something with it in GraphicsPanel instance
self._grphpnl.OnSerialText(text)
...
Somewhere else in your code:
class GraphicsPanel(wx.Panel):
...
def OnSerialText(text):
# do something with the text
That variable is defined at function scope. There is no way to get that value.
To make the value available to anything outside of the method you need to store the value on the class self.text = event.data or return the value return text
You need to decide what is right for the situation though, I'm guessing by the name of the function that returning the data is the right thing to do.
You need to return the value!
def OnSerialRead(self, event):
"""Handle input from the serial port."""
text = event.data
return text
Then you can access the value like this
marito = TerminalPanel.OnserialRead(event)
Or save the value in the class:
class Reader():
def OnSerialRead(...):
...
self.text = event.data
and then access the value from the class like so:
marito = Reader.text

Python Attribute Error with multiple classes and Tkinter

I'm trying create a gui using Tkinter that grabs a username and password and connects to a remote server and does a function. I slapped together some messy code and it more or less worked, but when I tried to recreate it in a tidy module, it broke. Its probably a newbie python error, but I can't spot it. EDIT: to clarify, when it worked, the only class was setupGui and any methods were under that class. Now that I've separated the gui from the methods, its not working.
class setupGui(object):
def __init__(self, parent):
##omited general frame stuff
self.userIn = ttk.Entry(self.topFrame, width = 20)
self.userIn.grid(row = 1, column = 1)
self.passIn = ttk.Entry(self.topFrame, width = 20, show ="*")
self.passIn.grid(row = 2, column = 1)
#Buttons
self.setupbtn = ttk.Button(self.topFrame, text = "Start Setup", command = setup().startSetup())
self.setupbtn.grid(row = 3, column = 0, pady = 10)
class setup(object):
def__init__(self):
self.userName = setupGui.userIn.get()
self.userPass = setupGui.passIn.get()
def startSetup(self):
self.another_related_fucntion # about 4 related functions actually
if __name__ == '__main__':
root = Tk()
gui = setupGui(root)
root.mainloop()
And if I don't have the command attached to the button, everything works fine (but obviously does diddly squat except look pretty). And when I attached the command, I get this error:
Traceback (most recent call last):
File "macSetup.py", line 211, in <module>
gui = setupGui(root)
File "macSetup.py", line 45, in __init__
self.setupbtn = ttk.Button(self.topFrame, text = "Start Setup", command = setup().startSetup())
File "macSetup.py", line 69, in __init__
self.userName = setupGui.userIn.get()
AttributeError: type object 'setupGui' has no attribute 'userIn'
In your code, userIn is set up as an instance variable of setupGui objects, not as an attribute of the setupGui class itself.
The simplest solution would be to merge the setupGui and setup classes to move startSetup in as a method of setupGui, then use command=self.startSetup when you initialize setupbtn—this calls startSetup as a bound method, and self should thus refer to the setupGui object, which you can then use e.g. self.userIn.get() and self.passIn.get() on.
If you'd rather keep the logic you have in the setup class out of the setupGui class, you can separate it out like this:
class setup(object):
def __init__(self, username, userpass):
self.userName = username
self.userPass = userpass
def startSetup(self):
# as before
then add this method to the setupGui class:
def dosetup(self):
setup(self.userIn.get(), self.passIn.get()).startSetup()
and instantiate the Button with command=self.dosetup. (I would personally make the setup class a standalone function, but I don't know how complicated your startSetup routine actually is, so I assume you have a good reason for making it a class.)
The command attribute takes a reference to a function, but you're calling the function and giving the result to the command attribute. The net result is that you're calling the setup function at the time that you create the button, not at the time that you click the button. Things aren't fully initialized yet, so you get the error.
You're doing this:
self.setupbtn = ttk.Button(self.topFrame, text = "Start Setup", command = setup().startSetup())
... when you should be doing something like this:
self.setupbtn = ttk.Button(self.topFrame, text = "Start Setup", command = setup().startSetup)
Note the lack of the trailing () on startSetup.
If you don't want to instantiate setup until the button is clicked, you have a couple of choices. The best, arguably, is to create a method:
def _launch_setup(self):
setup().setupGui()
...
self.setupbtn = ttk.Button(..., command=self._launch_setup)
You could also use a lambda, but in this case I recommend a named method.
The class setupGui itself doesn't have the attribute userIn.
In the __init__ method of setupGui you give the attribute to the instance, not the class.

pygtk gtk.Builder.connect_signals onto multiple objects?

I am updating some code from using libglade to GtkBuilder, which is supposed to be the way of the future.
With gtk.glade, you could call glade_xml.signal_autoconnect(...) repeatedly to connect signals onto objects of different classes corresponding to different windows in the program. However Builder.connect_signals seems to work only once, and (therefore) to give warnings about any handlers that aren't defined in the first class that's passed in.
I realize I can connect them manually but this seems a bit laborious. (Or for that matter I could use some getattr hackery to let it connect them through a proxy to all the objects...)
Is it a bug there's no function to hook up handlers across multiple objects? Or am I missing something?
Someone else has a similar problem http://www.gtkforums.com/about1514.html which I assume means this can't be done.
Here's what I currently have. Feel free to use it, or to suggest something better:
class HandlerFinder(object):
"""Searches for handler implementations across multiple objects.
"""
# See <http://stackoverflow.com/questions/4637792> for why this is
# necessary.
def __init__(self, backing_objects):
self.backing_objects = backing_objects
def __getattr__(self, name):
for o in self.backing_objects:
if hasattr(o, name):
return getattr(o, name)
else:
raise AttributeError("%r not found on any of %r"
% (name, self.backing_objects))
I have been looking for a solution to this for some time and found that it can be done by passing a dict of all the handlers to connect_signals.
The inspect module can extract methods using
inspect.getmembers(instance, predicate=inspect.ismethod
These can then be concatenated into a dictionary using d.update(d3), watching out for duplicate functions such as on_delete.
Example code:
import inspect
...
handlers = {}
for c in [win2, win3, win4, self]: # self is the main window
methods = inspect.getmembers(c, predicate=inspect.ismethod)
handlers.update(methods)
builder.connect_signals(handlers)
This will not pick up alias method names declared using #alias. For an example of how to do that, see the code for Builder.py, at def dict_from_callback_obj.
I'm only a novice but this is what I do, maybe it can inspire;-)
I instantiate the major components from a 'control' and pass the builder object so that the instantiated object can make use of any of the builder objects (mainwindow in example) or add to the builder (aboutDialog example). I also pass a dictionary (dic) where each component adds "signals" to it.
Then the 'connect_signals(dic)' is executed.
Of course I need to do some manual signal connecting when I need to pass user arguments to the callback method, but those are few.
#modules.control.py
class Control:
def __init__(self):
# Load the builder obj
guibuilder = gtk.Builder()
guibuilder.add_from_file("gui/mainwindow.ui")
# Create a dictionnary to store signal from loaded components
dic = {}
# Instanciate the components...
aboutdialog = modules.aboutdialog.AboutDialog(guibuilder, dic)
mainwin = modules.mainwindow.MainWindow(guibuilder, dic, self)
...
guibuilder.connect_signals(dic)
del dic
#modules/aboutdialog.py
class AboutDialog:
def __init__(self, builder, dic):
dic["on_OpenAboutWindow_activate"] = self.on_OpenAboutWindow_activate
self.builder = builder
def on_OpenAboutWindow_activate(self, menu_item):
self.builder.add_from_file("gui/aboutdialog.ui")
self.aboutdialog = self.builder.get_object("aboutdialog")
self.aboutdialog.run()
self.aboutdialog.destroy()
#modules/mainwindow.py
class MainWindow:
def __init__(self, builder, dic, controller):
self.control = controller
# get gui xml and/or signals
dic["on_file_new_activate"] = self.control.newFile
dic["on_file_open_activate"] = self.control.openFile
dic["on_file_save_activate"] = self.control.saveFile
dic["on_file_close_activate"] = self.control.closeFile
...
# get needed gui objects
self.mainWindow = builder.get_object("mainWindow")
...
Edit: alternative to auto attach signals to callbacks:
Untested code
def start_element(name, attrs):
if name == "signal":
if attrs["handler"]:
handler = attrs["handler"]
#Insert code to verify if handler is part of the collection
#we want.
self.handlerList.append(handler)
def extractSignals(uiFile)
import xml.parsers.expat
p = xml.parsers.expat.ParserCreate()
p.StartElementHandler = self.start_element
p.ParseFile(uiFile)
self.handlerList = []
extractSignals(uiFile)
for handler in handlerList:
dic[handler] = eval(''. join(["self.", handler, "_cb"]))
builder.connect_signals
({
"on_window_destroy" : gtk.main_quit,
"on_buttonQuit_clicked" : gtk.main_quit
})

Categories

Resources