5

Platform: Windows 10 QGis 2.18.14 QT Desiner 4.8.5 PyQT4

I'm creating a custom form using QT Designer to be used in a layer along with a routine in Python.

Just for testing I added a QgsColorButton element on the form.

The idea would be to select the color in the color options box of this button and the selected color would be saved in the attribute table of the layer's feature.

I tried to do a little routine in Python only to check if I could access the properties of the QgsColorButton when the form was opened, but can not even get through this phase.

Any tips to solve this problem?


In the console the code seems to be simple, but I have difficulty understanding with accessing the QgsColorButton widget of the form created in QT Designer.

This would be the form template with multiple QgsColorButton.

enter image description here

I need to access the QgSColorButton with something like the code below:

from qgis.core import *
from qgis.gui import *
from PyQt4.QtGui import *
from PyQt4.QtCore import *

def form_open (Dialog, layer_id, feature_id):
     global form
     form = Dialog
     btn = form.findChild (QgsColorButton, "mColorButton")
     btn.setColor (QColor (255, 0, 0, 127))
     layer = iface.activeLayer ()
     provider = layer.dataProvider ()
     feature = layer.selectedFeatures ()
     feature ['Color_01'] = btn.color ()
     layer.startEditing ()
     layer.updateFeature (feature)
     layer.commitChanges ()

The code above seems to be simple, but does not work as you like.

A second part code would be the QgsColorButton load the color saved in the attribute table when the form was opened.

I have no idea how to make this work!


@Francisco Raga, perfect! The only change I need to make is to change the LoadColor method.

def LoadColor ():
color_value = ToolFeature ["Color"]    
if not isinstance (color_value, QPyNullVariant):
mColorButton.setColor(color_value)
return

But this returned the following error.

Traceback (most recent call last):
   File "", line 1, in
   File "", line 22, in UpdateColorForm
   File "", line 29, in LoadColor
AttributeError: 'QPushButton' object has no attribute 'setColor'

When I enter the command below in the Python console of the QGIS dir (QgsColorButton) returns all methods of QgsColorButtom and the setColor method appears in the list

I compiled the ui template to check which methods and arguments I want to return to the method

self.mColorButton.setColor (QtGui.QColor (0, 0, 255))

I do not know what can be done, because in the QGIS console the setColor method is recognized and it runs the code perfectly.

I tried to use the code below, but nothing happens. No error message is displayed and the background of the mColorButton button does not change color with the value loaded from the "Color" attribute of the feature.

def LoadColor():
    color_value = ToolFeature["Color"]    
    if not isinstance(color_value, QPyNullVariant):
        style = "QWidget { background-color: %s; }" % color_value
        mColorButton.setAutoFillBackground(True)
        mColorButton.setStyleSheet(style)
        mColorButton.update()
    return
  • 1
    In QGIS 2.x you should use QgsColorButtonV2. It's the nicer button with the drop down for recently used and preset colors. – ndawson Nov 3 '17 at 8:01
5
+100

I've done a full documentation for all Python QGIS GUI classes

You can found out illustrated samples for both:

  • I've already looked at this site, but everyone is an example using the QGIS console. All the examples I've found on the internet are all generic made for console. My doubt is as I explored earlier. Multiple QgsColorButton on a form made in QT Designer as options to save the selected colors even after closing the form. I believe I have not written anything about this yet, as it has been some days that I am searching the internet for a solution and all I found are way examples made in the QGIS console. – Marcelo Ribeiro da Silva Nov 5 '17 at 2:35
  • 1
    That is a very comprehensive documentation! I wish this was linked from the official QGIS website as an extra resource as I only found it from this answer. – Joseph Nov 6 '17 at 12:01
4

You can try it out even without any custom Dialog because QgsColorButton has show() method (it is not a complex C++ class). So, at Python Console of QGIS:

>>>from qgis.gui import QgsColorButton
>>>w = QgsColorButton()
>>>w.move(500,500)
>>>w.setMinimumSize(300, 25)
>>>w.show()

and it was obtained some similar to:

enter image description here

After select #b36910 color (HTML notation) and click in OK, result was as follow:

enter image description here

Finally, again at Python Console with following code line:

>>>w.color().name()
u'#b36910'

it was corroborated name color of selection. This string can be saved in the attribute table of the layer's feature.

4

I think I understood your question. I have a layer that have a column "Color",the when open my dialog and select a color using QgsColorButton. ,this selected feature UPDATE the "Color" attribute using the selected color.

And the second goal is that,the selected attribute have a color in the "Color" attribute and my QgsColorButton Update the value using this.

This is my dialog:

enter image description here

And the test layer,that have a "Color" column

enter image description here

My compilated dialog have this signal:

QtCore.QObject.connect(self.mColorButton, QtCore.SIGNAL(_fromUtf8("colorChanged(QColor)")), BaseDialog.UpdateColor)

And my BaseDialog "Plugin dialog"

import os.path
from qgis.core import *
from qgis.gui import *
from PyQt4 import QtCore, QtGui
from PyQt4.QtCore import *
from PyQt4.QtGui import *
from gui.generated.ui_BaseDialog import Ui_BaseDialog


class BaseDialog(QtGui.QDialog, Ui_BaseDialog):
    def __init__(self, iface):
        QtGui.QDialog.__init__(self)
        self.setupUi(self)
        self.iface = iface
        self.plugin_dir = os.path.dirname(os.path.abspath(__file__))
        self.LoadColor()

    # Load color from attribue
    def LoadColor(self):
        selected_features = self.iface.activeLayer().selectedFeatures()
        for color in selected_features:
            color_value=color["Color"]
            self.mColorButton.setColor(QColor(color_value))
        return

    # Update lineEdit
    def UpdateColor(self,color):
        self.lineEdit.setText(color.name())
        self.UpdateFeature(color)
        return

    # Update Attribute value
    def UpdateFeature(self,color):
        layer = self.iface.activeLayer()
        provider = layer.dataProvider()
        fldIdx = provider.fieldNameIndex("Color") # Get Column
        features = layer.selectedFeatures()
        if not features:
            return
        layer.startEditing()
        for feature in features:
            feature[fldIdx] = color.name()
            layer.updateFeature(feature)

        layer.commitChanges()
        return

Then when open dialog and I have any selected feature and this feature have any value in attribute column,this is loaded to ColorButton.

Add gif.

enter image description here

NOTE: If have this error when compile your .ui

ImportError: No module named qgscolorbutton

Open the .ui using some text editor and replace:

<customwidgets>
  <customwidget>
   <class>QgsColorButton</class>
   <extends>QPushButton</extends>
   <header>qgscolorbutton.h</header>
  </customwidget>
 </customwidgets>

with:

 <customwidgets>
  <customwidget>
   <class>QgsColorButton</class>
   <extends>QPushButton</extends>
   <header>qgis.gui</header>
  </customwidget>
 </customwidgets>

And compile again.


UPDATE: Create a Python init function: "Provide code in this dialog"

I'm not sure if this alternative for your example can help you,but you only need one .ui file and only one script.

I have a simple .ui

enter image description here

And my python init function is : Note that combobox have selected "Provide code in this dialog"

enter image description here

Code:

from PyQt4.QtCore import *
from PyQt4.QtGui import *
from qgis.PyQt.QtWidgets import QWidget


mColorButton=None
lineEdit=None
ToolFeature=None
ToolLayer=None


def UpdateColorForm(dialog, layer, feature):
    global ToolFeature
    global ToolLayer
    global mColorButton
    global lineEdit
    ToolFeature = feature
    ToolLayer = layer
    mColorButton = dialog.findChild(QWidget, "mColorButton")
    lineEdit = dialog.findChild(QLineEdit, "lineEdit")
    mColorButton.connect(mColorButton, SIGNAL("colorChanged(QColor)"), UpdateColor)
    LoadColor()


def LoadColor():
    color_value = ToolFeature["Color"]
    if not isinstance(color_value, QPyNullVariant):
        lineEdit.setText(color_value)
    return


def UpdateColor(color):
    lineEdit.setText(color.name())
    UpdateFeature(color)
    return


def UpdateFeature(color):
    provider = ToolLayer.dataProvider()
    fldIdx = provider.fieldNameIndex("Color")
    ToolLayer.startEditing()
    ToolFeature[fldIdx] = color.name()
    ToolLayer.updateFeature(ToolFeature)
    ToolLayer.commitChanges()
    return

You don't need compile .ui or something like that,and when change the value ,change the attibute and when open dialog,load current value in the lineedit.

enter image description here

If you prefer update the value when click on Ok button need change the signals ,read this,and remove the current UpdateColor signal

UPDATE 2 : Using QPushButton widget

Is so strange but QgsColorButton is not accessible, but we can solve this by using a simple qpushbutton

from PyQt4.QtCore import *
from PyQt4.QtGui import *
from qgis.PyQt.QtWidgets import QWidget

mColorButton = None
lineEdit = None
ToolFeature = None
ToolLayer = None


def UpdateColorForm(dialog, layer, feature):
    global ToolFeature
    global ToolLayer
    global mColorButton
    global lineEdit

    ToolFeature = feature
    ToolLayer = layer
    mColorButton = dialog.findChild(QWidget, "pushButton")
    mColorButton.clicked.connect(color_picker)

    # Default Color
    UpdateColorPicker("#2b71e2")

    lineEdit = dialog.findChild(QLineEdit, "lineEdit")
    LoadColor()


def color_picker():
    color_value = QColorDialog.getColor()
    if color_value.isValid():
        UpdateColor(color_value)
    return


def LoadColor():
    color_value = ToolFeature["Color"]
    if not isinstance(color_value, QPyNullVariant):
        lineEdit.setText(color_value)
        UpdateColorPicker(color_value)
    return


def UpdateColorPicker(color):
    style = """
            QWidget {
            background-color:  %s;
            border-style: outset;
            border-width: 2px;
            border-radius: 10px;
            border-color: beige;
            font: bold 14px;
            min-width: 10em;
            padding: 6px;
            } """ % color
    mColorButton.setAutoFillBackground(True)
    mColorButton.setStyleSheet(style)
    mColorButton.update()
    return


def UpdateColor(color):
    lineEdit.setText(color.name())
    UpdateFeature(color)
    UpdateColorPicker(color.name())
    return


def UpdateFeature(color):
    provider = ToolLayer.dataProvider()
    fldIdx = provider.fieldNameIndex("Color")
    ToolLayer.startEditing()
    ToolFeature[fldIdx] = color.name()
    ToolLayer.updateFeature(ToolFeature)
    ToolLayer.commitChanges()
    return

and the result work perfectly.

I hope it helps

Tested using Windows 10 QGis 2.18.14

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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