0

QGIS 3.36.2 with Python 3.12.3

Users draw a QgsAnnotationLineItem or QgsAnnotationPolygonItem on a QgsAnnotationLayer my script creates, once they're done and press a button, the script reads the item's coordinates. However, QgsAnnotationLineItem draws a really thin, light red polyline, which is quite hard to see, so I want to change not only the default width but also the default color for all polylines and the default line and fill color for all polygons drawn by the user.

With a regular QgsVectorLayer I'd create a QgsMarkerSymbol, modify it and its QgsSymbolLayer however I want, then assign it to the layer's QgsFeatureRenderer. QgsAnnotationLayer doesn't contain a renderer like that, instead it only inherits a QgsAbstract3DRenderer, which is probably not the right thing to use (no matching functions, according to the docs).

I thought about creating a polygon and polyline myself to modify them and delete them again afterwards, hoping that that would set the default style:

self.layer = QgsAnnotationLayer(self.layername,QgsAnnotationLayer.LayerOptions(QgsProject.instance().transformContext()))
self.layer.setCrs(self.crs)

line = QgsAnnotationLineItem.create()
geo1 = QgsLineString(pointarray1)
line.setGeometry(geo1)
symbol1 = line.symbol() #QgsLineSymbol
symbol1.setWidth(1) #Default: 0.26
symbol1.setColor(QColor(0,100,255,255)) #Blue
self.layer.addItem(line)

polygon = QgsAnnotationPolygonItem.create()
geo2 = QgsPolygon(QgsLineString(pointarray2))
polygon.setGeometry(geo2)
symbol2 = polygon.symbol() #QgsFillSymbol
symbollayer = symbol2.symbolLayer(0) #QgsSimpleFillSymbolLayer
symbollayer.setFillColor(QColor(0,255,0,255)) #Fill Color = Inside #Green
symbollayer.setStrokeColor(QColor(255,0,255,255)) #StrokeColor = Border #Magenta
symbollayer.setStrokeWidth(0.5) #Default: 0.26
self.layer.addItem(polygon)

QgsProject.instance().addMapLayer(self.layer)
self.layer.reset()

This draws a polygon and polyline in the correct colors and instantly removes them again but it seems to be pretty random if this then also affects the color,... of the annotations I draw manually (as the user would). The few times it did work (only three times out of many tries so far), only the polyline used the correct settings, the polygon always used the default, thin, black border, instead of the custom stroke color and width I'd set.

How do I programmatically set the default style for all polygons or poly lines my users draw?

1 Answer 1

0

I got help from the North Road team who developed the "Annotations" plugin:

There are two different "themes":

1. The colors that are used while a polygon or polyline is being drawn (before it's finalized).

These use the "Rubberband" colors in "Settings - Options - Map Tools - Digitizing". Set them in code with:

strokeColor = QColor(255,0,0,255) #Full red
fillColor = QColor(255,0,0,127) #50% transparent red
settings = QgsSettings()
settings.setValue('digitizing/line-width',2)
settings.setValue('digitizing/line-color',strokeColor)
settings.setValue('digitizing/fill-color',fillColor)

This still uses the default "dashed line" style and I haven't found the setting to change it to an e.g. dotted or solid style yet, so if anyone knows how to do that, please write a comment.

I don't know what else these colors are used for/by, apart from drawing annotations. Changes are permanent, QGIS remembers the new colors even after a restart, so it's a good idea (to save the default values somewhere and) to reset them to default in your plugin's unload function:

#Default style in QGIS 3.36.2
settings = QgsSettings()
settings.setValue('digitizing/line-width',1)
settings.setValue('digitizing/line-color',QColor.fromRgbF(1,0,0,0.78))
settings.setValue('digitizing/fill-color',QColor.fromRgbF(1,0,0,0.12))

2. The colors that are used when the polygon or polyline is completed with a right-click.

This works in a similar way to how you would change the style of your layer, except that it uses the application's QgsRecentStyleHandler instead of the layer's QgsFeatureRenderer (I don't know what other elements are affected by this either):

default_polygon = QgsFillSymbol()
#default_polygon.setColor(QColor(0,255,0,255)) #Fill Color = Inside
symbollayer = default_polygon.symbolLayer(0) #QgsSimpleFillSymbolLayer
symbollayer.setFillColor(QColor(0,0,255,120)) #50% transparent red
symbollayer.setStrokeColor(QColor(255,0,0,255)) #Red
symbollayer.setStrokeWidth(0.5) #Default: 0.26

default_line = QgsLineSymbol()
#symbollayer = default_line.symbolLayer(0) #QgsSimpleLineSymbolLayer
default_line.setColor(QColor(255,0,0,255)) #Stroke color #Red
default_line.setWidth(0.5) #Default: 0.26

rch = QgsApplication.recentStyleHandler()
rch.pushRecentSymbol('polygon_annotation_item', default_polygon)
rch.pushRecentSymbol('line_annotation_item', default_line)
#rch.pushRecentSymbol('marker_annotation_item', default_marker)

This is per "session" per layer, so if you change the color a second time while the old layer is still there, then it won't use the new color. You have to delete the layer, then restart the script or restart QGIS.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.