6

Can I change the width of the drop-down field (attribute) list in the attribute table that is used for editing, i.e. the highlighted drop-down in the image below with the value "ID"? The list is so narrow I can't see field names easily. enter image description here

2
  • Unfortunately that didn't help.
    – Oisin
    Nov 28, 2023 at 9:58
  • 1
    I have tried this again today and yours (Taras) and Louis's solutions now both work. I think there must have been some sort of corruption in my project file - before trying today I had recreated the project. Mnay thanks for your help.
    – Oisin
    Nov 29, 2023 at 10:54

2 Answers 2

6

There is a PyQGIS solution I can suggest. Honestly, it was tricky, and not straightforward.

The thing you are looking for is the QFrame hidden under AttributeTable / mUpdateExpressionBox / mFieldCombo. It has a corresponding method for that called setFixedWidth().

Let's assume there is a point layer with an opened attribute table in edited mode, see the below:

input

The default width of this drop-down list is 100, possible to see by means of the width() method.

Proceed with Plugins > Python Console > Show Editor and paste the script below:

# imports
from qgis.utils import iface
from qgis.core import QgsProject
from PyQt5.QtWidgets import QApplication, QFrame

# accessing layer by its name
layer = QgsProject.instance().mapLayersByName("points_in_polygon")[0]

# looking for the attribute table widget
all_widgets = QApplication.instance().allWidgets()
attribute_table_widgets = [widget for widget in all_widgets if "AttributeTable" in widget.objectName() and layer.name() in widget.objectName()]

# if layer has no opened attribute table, open it
if len(attribute_table_widgets) == 0:
    iface.showAttributeTable(layer)
    all_widgets = QApplication.instance().allWidgets()
    attribute_table_widgets = [widget for widget in all_widgets if "AttributeTable" in widget.objectName() and layer.name() in widget.objectName()]

# finding attribute table widget that matches layer name 
for widget in attribute_table_widgets:
    # looping over elements of the layer's attribute table
    for elem1 in widget.children():
        if elem1.objectName() == 'mUpdateExpressionBox':
            for elem2 in elem1.children():
                if elem2.objectName() == 'mFieldCombo':
                    for elem3 in elem2.children():
                        if isinstance(elem3, QFrame):
                            # here change to desired width value
                            elem3.setFixedWidth(500)

Change the name of your input layer. Press Run script run script and get the output that will look like this:

result

Now the new width is 500.

This solution will work as long as you keep your attribute table open, does not matter if it will be edited multiple times.

Perhaps, there is more easier way to exist.

P.S. I would appreciate it if someone could try this code.


References:

8
  • 1
    That is one very ugly for loop ... Also doesn't work for me on 3.22.11
    – Kalak
    Nov 24, 2023 at 8:02
  • Fully agree with you :) you can suggest a better one anytime
    – Taras
    Nov 24, 2023 at 8:18
  • I was working on it, its coming.
    – Kalak
    Nov 24, 2023 at 8:20
  • 1
    The attribute table is a PyQt5.QtWidgets.QDialog class. I suppose we can omit it. Because "Returns true if the widget is an independent window, otherwise returns false.".
    – Taras
    Nov 24, 2023 at 8:43
  • 1
    I updated this answer also so it opens the attribute table even if there is an attribute table of another layer already open
    – Kalak
    Nov 24, 2023 at 12:58
4

To complement @Taras's answer with a simpler python code (changed with edit):

# imports
from qgis.utils import iface
from qgis.core import QgsProject
from PyQt5.QtWidgets import QApplication, QFrame

# accessing layer by its name
layer = QgsProject.instance().mapLayersByName("points_in_polygon")[0]

# looking for the attribute table widget
all_widgets = QApplication.instance().allWidgets()
attribute_table_widgets = [
    widget for widget in all_widgets 
    if "AttributeTable" in widget.objectName()
    and layer.id() in widget.objectName()
]

# if layer has no opened attribute table, open it
if len(attribute_table_widgets) == 0:
    iface.showAttributeTable(layer)
    all_widgets = QApplication.instance().allWidgets()
    attribute_table_widgets = [
        widget 
        for widget in all_widgets 
        if "AttributeTable" in widget.objectName()
        and layer.id() in widget.objectName()
    ]

# finding attribute table widget that matches layer name 
for widget in attribute_table_widgets:
    # get the right combo box of the layer's attribute table
    update_expression_box = widget.findChild(QFrame, "mUpdateExpressionBox")
    combo_box = update_expression_box.findChild(QComboBox, "mFieldCombo")
    
    # change the width of the entire combo box
    combo_box.setFixedWidth(500)
    
    # or to only change the width of the drop-down list (same as @Taras)
    # drop_down_list = combo_box.findChild(QFrame, "")
    # drop_down_list.setFixedWidth(500)

EDIT:

The name of the layer cannot contain "-" (or be different than the source name of the layer) otherwise the condition layer.name() in widget.objectName() will fail.

Because it check that the layer name is in the object name of the QgsAttributeTableDialog object which is built like so: "QgsAttributeTableDialog/@layer_id". The problem being that "-" cannot exist in the @layer_id. Meaning that "-" in the layer name are converted to "_" in the layer id.

The solution being that using layer.id() will work more reliably than layer.name()

14
  • Exactly! I was thinking about the findChild or findChildren method
    – Taras
    Nov 24, 2023 at 8:49
  • 1
    I though about directly using findChildren which does recursive search but there are two QComboBox with name "mFieldCombo" with different intermediary parents making it just simpler to just do it in two steps
    – Kalak
    Nov 24, 2023 at 8:51
  • A great adding with combo_box.setFixedWidth(500) :)
    – Taras
    Nov 24, 2023 at 8:53
  • I can't get this to work for me. No error, but nothing happens
    – Oisin
    Nov 24, 2023 at 12:32
  • 1
    @Louis Now working - I think the Project was corrupted. I recreated it and it is now working. Thanks for all your help.
    – Oisin
    Nov 29, 2023 at 10:55

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.