How to draw lines in IronPython with Winforms? - python

I've started working with IronPython in #Develop, and i love the integration with IronPython and Windows Forms, it lets you create the GUI like is were Visual Basic or C#
The question i have is simple, how to draw a line into a PictureBox when it's clicked? I've found this code about drawing lines, but i know how to adapt it to a PictureBox.
This is the code i've found:
http://www.zetcode.com/tutorials/ironpythontutorial/painting/
So, what should i put in "def PictureBox1Click(self, sender, e):"?
Any help or guide would be gratly appreciated.

Here is a simple example that draws a line on a picture box when it is clicked.
import System.Drawing
import System.Windows.Forms
from System.Drawing import *
from System.Windows.Forms import *
class MainForm(Form):
def __init__(self):
self.InitializeComponent()
self.pen = System.Drawing.Pen(System.Drawing.Color.Black);
def InitializeComponent(self):
self._pictureBox1 = System.Windows.Forms.PictureBox()
self._pictureBox1.BeginInit()
self.SuspendLayout()
#
# pictureBox1
#
self._pictureBox1.Location = System.Drawing.Point(13, 13)
self._pictureBox1.Name = "pictureBox1"
self._pictureBox1.Size = System.Drawing.Size(259, 237)
self._pictureBox1.TabIndex = 0
self._pictureBox1.TabStop = False
self._pictureBox1.Click += self.PictureBox1Click
#
# MainForm
#
self.ClientSize = System.Drawing.Size(284, 262)
self.Controls.Add(self._pictureBox1)
self.Name = "MainForm"
self.Text = "PyWinForm"
self._pictureBox1.EndInit()
self.ResumeLayout(False)
def PictureBox1Click(self, sender, e):
g = self._pictureBox1.CreateGraphics()
g.DrawLine(self.pen, 10, 10, 400, 200)

Related

PyQgis: item is not the expected type on a QgsMapCanvas

I am currently working on a PyQgis based standalone application and I need to add various QgsRubberBand to my Canvas.
I made a subclass of it : LineAnnotation.
The problem is that when I use the method "QgsMapCanvas.itemAt(event.pos() )" on a "canvasPressEvent", it returns a "qgis._gui.QgsRubberBand" object, not a "LineAnnotation".
Did I do something wrong ? The rest of my program can't work if it doesn't recognize that it's a LineAnnotation as it contains several new methods that I need to use.
Also I can't interact with the item at all, if I try to use one of the methods from QgsRubberBand, the application crashes.
Here is the code with the problem:
from qgis.gui import QgsMapCanvas, QgsLayerTreeMapCanvasBridge, QgsRubberBand
from qgis.core import QgsApplication, QgsProject, QgsPointXY, QgsGeometry
from qgis.PyQt.QtGui import QColor
import sys
class LineAnnotation(QgsRubberBand):
def __init__(self, canvas):
QgsRubberBand.__init__(self, canvas)
self.setColor(QColor("red") )
self.setWidth(10)
class Interface(QgsMapCanvas):
def __init__(self):
QgsMapCanvas.__init__(self)
self.setCanvasColor(QColor("#182F36") )
project_path = "project_path"
project = QgsProject.instance()
project.read(project_path)
layer_tree = QgsLayerTreeMapCanvasBridge(project.layerTreeRoot(), canvas=self)
layer_tree.setAutoSetupOnFirstLayer(False)
self.zoomToFeatureExtent(project.mapLayersByName('layer_name')[0].extent() )
self.enableAntiAliasing(True)
self.setAcceptDrops(True)
self.setParallelRenderingEnabled(True)
p1 = QgsPointXY(524670.46860305720474571, 5470375.41737424582242966)
p2 = QgsPointXY(589864.10151600651443005, 5487531.63656186405569315)
r = LineAnnotation(self)
r.setToGeometry(QgsGeometry.fromPolylineXY([p1, p2]) )
def mousePressEvent(self, event) -> None:
item = self.itemAt(event.pos() )
print(type(item) )
# Output is "<class 'qgis._gui.QgsRubberBand'>"
# Expected: "<class 'LineAnnotation'>"
class StackOverflow:
def __init__(self):
qgs = QgsApplication([], True)
qgs.setDoubleClickInterval(250)
qgs.initQgis()
graphicUI = Interface()
graphicUI.showMaximized()
sys.exit(qgs.exec_() )
if __name__ == '__main__':
app = StackOverflow()
> output: \<class 'qgis.\_gui.QgsRubberBand'\>
> Desired output: \<class 'lineAnnotation.LineAnnotation'\>
Problem seems to occur in versions prior to Qgis 3.26, my problem was solved after updating to latest version (3.28).

Meshcat not showing the changes to a Free Body's Pose

I've been trying to create my own ManipulationStation for a different robot arm using Pydrake, but I've been unsuccessful so far in adding clutter to my ManipulationStation. For some odd reason, Meshcat won't show the updated poses of my objects.
import numpy as np
import glob
from pydrake.geometry import MeshcatVisualizerCpp
from pydrake.math import RigidTransform, RotationMatrix
from pydrake.systems.analysis import Simulator
from pydrake.systems.framework import DiagramBuilder
from pydrake.all import (
DiagramBuilder, FindResourceOrThrow,
SceneGraph, Diagram,
MultibodyPlant, Parser, Simulator, MeshcatVisualizerCpp,
UniformlyRandomRotationMatrix, RandomGenerator)
from pydrake.geometry import Meshcat
class DexterPPStation(Diagram):
def __init__(self, time_step, file_path):
super().__init__()
self.time_step = time_step
self.path = file_path
self.plant = MultibodyPlant(self.time_step)
self.scene_graph = SceneGraph()
self.plant.RegisterAsSourceForSceneGraph(self.scene_graph)
self.controller_plant = MultibodyPlant(self.time_step)
self.object_ids = []
self.object_poses = []
def AddObject(self, file, name, pose):
model_idx = Parser(self.plant).AddModelFromFile(file, name)
indices = self.plant.GetBodyIndices(model_idx)
self.object_ids.append(indices[0])
self.object_poses.append(pose)
return model_idx
def CreateBins(self, path, XP_B1, XP_B2):
bin1 = Parser(self.plant).AddModelFromFile(path, "bin1")
self.plant.WeldFrames(self.plant.world_frame(), self.plant.GetFrameByName("bin_base", bin1), XP_B1)
bin2 = Parser(self.plant).AddModelFromFile(path, "bin2")
self.plant.WeldFrames(self.plant.world_frame(), self.plant.GetFrameByName("bin_base", bin2), XP_B2)
def CreateRandomPickingObjects(self, n = 4):
choices = [f for f in glob.glob("/opt/drake/share/drake/manipulation/models/ycb/sdf/*.sdf")]
z = 0.1
rs = np.random.RandomState()
generator = RandomGenerator(rs.randint(1000))
for i in range(n):
obj = choices[i]
pose = RigidTransform(
UniformlyRandomRotationMatrix(generator),
[rs.uniform(.35,0.6), rs.uniform(-.2, .2), z])
model = self.AddObject(obj, obj.split("/")[-1].split(".")[0] + str(i), pose)
body_idx = self.plant.GetBodyIndices(model)[0]
self.object_ids.append(body_idx)
self.object_poses.append(pose)
z+=0.1
def SetRandomPoses(self, station_context):
plant_context = self.GetSubsystemContext(self.plant, station_context)
for i in range(len(self.object_ids)):
self.plant.SetFreeBodyPose(plant_context, self.plant.get_body(self.object_ids[i]), self.object_poses[i])
def Finalize(self):
self.plant.Finalize()
self.controller_plant.Finalize()
builder = DiagramBuilder()
builder.AddSystem(self.plant)
builder.AddSystem(self.controller_plant)
builder.AddSystem(self.scene_graph)
builder.Connect(self.plant.get_geometry_poses_output_port(), self.scene_graph.get_source_pose_port(self.plant.get_source_id()))
builder.Connect(self.scene_graph.get_query_output_port(), self.plant.get_geometry_query_input_port())
builder.ExportOutput(self.scene_graph.get_query_output_port(), "query_object")
builder.ExportOutput(self.plant.get_geometry_poses_output_port(), "geometry_poses")
builder.ExportOutput(self.scene_graph.get_query_output_port(), "geometry_query")
builder.ExportOutput(self.plant.get_contact_results_output_port(),"contact_results")
builder.ExportOutput(self.plant.get_state_output_port(),"plant_continuous_state")
builder.BuildInto(self)
To test my code, I've been running the script below.
def test():
builder = DiagramBuilder()
station = DexterPPStation(1e-4, "drake/manipulation/models/final_dexter_description/urdf/dexter.urdf")
station.CreateBins("/opt/drake/share/drake/examples/manipulation_station/models/bin.sdf", RigidTransform(np.array([0.5,0,0])), RigidTransform(np.array([0,0.5,0])))
station.CreateRandomPickingObjects(1)
station.Finalize()
builder.AddSystem(station)
station_context = station.CreateDefaultContext()
station.SetRandomPoses(station_context)
MeshcatVisualizerCpp.AddToBuilder(builder, station.GetOutputPort("query_object"), meshcat)
diagram = builder.Build()
simulator = Simulator(diagram)
simulator.set_target_realtime_rate(1.0)
simulator.AdvanceTo(0.1)
test()
I've tried to call the SetRandomPoses() function from inside my Finalize() method, but since I needed to pass in a context to the function, I wasn't sure what to do. I'm new to Drake, so any input would be greatly appreciated.
You've created a station_context and set it to the random poses, but then you don't use it anywhere. When you create the simulator, it is creating another Context (with the default values), which is getting published when you call AdvanceTo.
The solution here, I think, is to not create your own station_context, but do e.g.
simulator = Simulator(diagram)
diagram_context = simulator.get_mutable_context()
station_context = station.GetMyMutableContextFromRoot(diagram_context)
station.SetRandomPoses(station_context)
then you can call AdvanceTo.

How to center printed text with pyfiglet in Python

I would want to print on the center text that has been made with py-figlet (https://github.com/pwaller/pyfiglet).
My code looks like this:
from pyfiglet import Figlet
f = Figlet(font='ascii___')
def DrawText(text):
return f.renderText(text)
print(DrawText('text')) <- Center it
On output I would want to have text printed on center with pyfiglet printing.
You can smartly use .center() with shutil module:
from pyfiglet import Figlet
import shutil
f = Figlet(font='ascii___')
def DrawText(text,center=True):
if center:
print(*[x.center(shutil.get_terminal_size().columns) for x in f.renderText(text).split("\n")],sep="\n")
else:
print(f.renderText(text))
DrawText('text',center=True)
You can use the keyword justify with 'auto', 'left', 'center', or 'right'
I did this:
import pyfiglet
txt = "title"
banner = pyfiglet.figlet_format(txt, font="slant", justify="center")
print(banner)
I couldn't find a decent documentation of the module.
So I had to dig through the code, and found the keywords for the FigletBuilder class constructor. It starts like this:
class FigletBuilder(object):
"""
Represent the internals of the build process
"""
def __init__(self, text, font, direction, width, justify):
self.text = list(map(ord, list(text)))
self.direction = direction
self.width = width
self.font = font
self.justify = justify
the OptionParser in the main() function (currently line 865), also gives an indication on how to use the keywords, just in case you want to learn more about how to use the keyword arguments, but don't want to scroll through about 1000 lines of code ^^

Python AttributeError : Object has no attribute in QGIS Plugin

I'm trying to create a GUI with QT Designer. I've converted my .ui designer file to a .py.
Here is my code:
from PyQt4.QtCore import QSettings, QTranslator, qVersion, QCoreApplication
from PyQt4.QtGui import QAction, QIcon
from qgis.core import *
import resources
from delete_feature_dialog import DeleteFeatureDialog
import os.path
class DeleteFeature:
def __init__(self, iface):
# Save reference to the QGIS interface
self.iface = iface
# Declare instance attributes
self.actions = []
self.menu = self.tr(u'&DeleteFeature')
self.toolbar = self.iface.addToolBar(u'DeleteFeature')
self.toolbar.setObjectName(u'DeleteFeature')
def add_action(
self,
icon_path,
text,
callback,
enabled_flag=True,
add_to_menu=True,
add_to_toolbar=True,
status_tip=None,
whats_this=None,
parent=None):
# Create the dialog (after translation) and keep reference
self.dlg = DeleteFeatureDialog()
....
return action
def initGui(self):
icon_path = ':/plugins/DeleteFeature/icon.png'
self.add_action(
icon_path,
text=self.tr(u''),
callback=self.run,
parent=self.iface.mainWindow())
def run(self):
#this code will populate the combo box with all vector layer
self.dlg.layerListCombo.clear()
layers = self.iface.legendInterface().layers()
layer_list = []
for layer in layers:
layerType = layer.type()
if layerType == QgsMapLayer.VectorLayer:
layer_list.append(layer.name())
self.dlg.layerListCombo.addItems(layer_list)
# show the dialog
self.dlg.show()
# Run the dialog event loop
result = self.dlg.exec_()
# See if OK was pressed
if result:
# Do something useful here - delete the line containing pass and
# substitute with your code.
selectedLayerIndex = self.dlg.layerlistcombo.currentIndex()
selectedLayer = layers [selectedLayerIndex]
.....
Then when I open the plugin, I get the following error:
'DeleteFeatureDialog' objectObject has no attribute
'layerlistcombo'in QGIS Plugin
Any suggestion for this.
Seems that you wrote:
selectedLayerIndex = self.dlg.layerlistcombo.currentIndex()
but you should have written:
selectedLayerIndex = self.dlg.layerListCombo.currentIndex()
Like you did previously in your code (notice the Camel Notation when writing, not just lower-case letters), which is probably causing the No Attribute error you get.

RuntimeError: deleteUI: Object 'Animation_Copy_Tool' not found

Getting this error when pressing the "Close Window" button in my UI. This button should delete the UI window but isn't. Full traceback:
Error: deleteUI: Object 'Animation_Copy_Tool' not found.
Traceback (most recent call last):
File "", line 36, in closeBtnCmd
RuntimeError: deleteUI: Object 'Animation_Copy_Tool' not found. #
# Animation Copy Tool
# Bakari Holmes 5/7/2015
# This is designed to copy and existing animation
# from one rig to another and make the process easier
# with a simple UI
import maya.cmds as mc
import functools
import maya.mel as mm
import pprint
class AnimCopyWindow(object):
##classmethod
def showUI(cls):
win = cls()
win.create()
return win
def __init__(self):
self.window = "Animation Copy Tool"
self.title = "Animation Copier"
self.size = (546,350)
def pasteTheseKeys(self, *args):
self.offsetVal = mc.intFieldGrp(self.int_offset, q=True, value1=True)
self.selObj_pasteKeys = mc.ls(sl=True)
for objectQuant in self.selObj_pasteKeys:
print objectQuant
self.ct = mc.currentTime(query = True)
self.t = self.ct + self.offsetVal
mc.currentTime(self.t)
# mc.selectKey(selObj_pasteKeys[objectQuant])
mc.pasteKey(time=(self.t,self.t), f=(1.0,1.0), option="merge", copies=1, to=0, fo=0, vo=0)
def closeBtnCmd(self,*args):
mc.deleteUI(self.window,window=True)
def create(self):
# check to see if window exists already
if mc.window(self.window,exists=True):
mc.deleteUI(self.window,window=True)
self.window = mc.window(self.window, title=self.title,widthHeight=self.size,menuBar=True)
self.copyAnim = mc.window(title="Transfer Animation Tool", backgroundColor=[0.3,0.3,0.3],sizeable=False,resizeToFitChildren=True)
#set the layout for UI
mc.columnLayout(adjustableColumn=True)
self.tx_src = mc.textFieldGrp(label="Source Object", editable=False, text=sel[0])
self.int_offset = mc.intFieldGrp(label="Frame Offset Amount", value1=0)
#add paste animation button
self.btn1 = mc.button(label="PASTE ANIMATION", command=self.pasteTheseKeys, bgc=[0.1,0.1,0.5])
#add close button window
self.btn2 = mc.button(label="CLOSE WINDOW", command=self.closeBtnCmd, bgc=[0.2,0.2,0.2])
mc.showWindow()
#################################
#####end of class definition#####
#################################
def keys_as_dictionary(channel):
"""return a dictionay of times:values for <channel>"""
keys = mc.keyframe(channel, q=True, tc=True) or []
values = mc.keyframe(channel, q=True, vc=True) or []
return dict(zip(keys, values))
def channels():
"""return a dictionary of <plug>:<channel_dict> for each animated plug selected"""
keys = mc.keyframe(sl=True, n=True, q=True)
result = {}
for k in keys:
plugs = mc.listConnections(k, p=True)[0]
result[plugs]= keys_as_dictionary(k)
return result
#store selected object info
sel = mc.ls(selection=True)
if (len(sel) != 1):
mm.eval("warning Must select one animated object;")
else:
mc.copyKey()
win = AnimCopyWindow()
win.create()
pprint.pprint(channels())
This error almost always means your UI element is not named what you think it is: Maya will automatically rename the items to make sure that no two siblings have the same name -- you can ask for "my_window" and get back "my_window123" . So you need to capture the actual name that is returned from cmds.window() or whatever ui command you use and delete that. Hard coded names are never reliable

Categories