Add dynamic column management and zoom features#12
Conversation
- Add right-click context menu for column operations (add/rename/remove) - Implement zoom options in View menu (1:1, fit, in, out) - Auto-fit image on window resize when zoom to fit is active - Add Quit option to File menu - Fix column auto-resize for all column operations - Remove redundant f.close() calls - Update AGENTS.md with dynamic column management instructions
📝 WalkthroughWalkthroughThis pull request introduces dynamic rating column management and zoom functionality to the PyQt5-based image quality control application. It replaces wildcard imports with explicit Qt imports, refactors CSV loading, adds keyboard-driven column editing via a header context menu, implements zoom/fit-to-window controls, and updates UI definitions accordingly. Documentation is added via AGENTS.md. Changes
Sequence DiagramsequenceDiagram
participant User
participant UI as MainWindow
participant Menu as Context Menu
participant Table as QTableWidget
User->>UI: Right-click table header
UI->>Menu: showColumnContextMenu()
Menu->>User: Display "Add/Rename/Remove Column"
alt Add Column
User->>Menu: Select "Add Column"
Menu->>UI: addColumn()
UI->>Table: Insert new column
UI->>Table: Update headers
UI->>Table: Fill cells for all rows
Table->>UI: Refresh display
else Rename Column
User->>Menu: Select "Rename Column"
Menu->>UI: renameColumn()
UI->>UI: Prompt for new name
UI->>Table: Update header text
Table->>UI: Refresh display
else Remove Column
User->>Menu: Select "Remove Column"
Menu->>UI: Confirm removal
UI->>Table: Remove selected column
UI->>Table: Update headers
Table->>UI: Refresh display
end
UI->>User: Updated table with modified columns
Estimated code review effort🎯 4 (Complex) | ⏱️ ~50 minutes
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Pull request overview
Adds UI and runtime support for managing QC rating columns at runtime and introduces explicit zoom controls (menu actions + resize-to-fit behavior), along with dependency/doc updates.
Changes:
- Adds column-management UI (Columns menu + custom header/table context menu) and supporting handlers.
- Adds View menu zoom actions (1:1, fit, in/out) plus window-resize handling to re-fit when appropriate.
- Introduces
uv.lockand updates agent documentation/codegen notes.
Reviewed changes
Copilot reviewed 4 out of 5 changed files in this pull request and generated 8 comments.
Show a summary per file
| File | Description |
|---|---|
window1.ui |
Adds context-menu policy, new menus/actions (File/View/Columns), splitter handle width; attempts to cap table width. |
window1.py |
Regenerates UI bindings for new menus/actions and context-menu policy; adjusts splitter/table sizing. |
PyQC.py |
Wires new menu actions, implements zoom + column add/rename/remove + CSV parsing updates for dynamic columns. |
uv.lock |
Adds uv lockfile capturing resolved dependencies (PyQt5, sip, Qt5). |
AGENTS.md |
Documents setup, codegen workflow, and dynamic column management usage. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| <property name="maximumSize"> | ||
| <size> | ||
| <width>500</width> | ||
| <height>16777215</height> | ||
| </size> | ||
| </property> | ||
| <property name="maximumSize"> | ||
| <size> | ||
| <width>16777215</width> | ||
| <height>16777215</height> | ||
| </size> | ||
| </property> |
There was a problem hiding this comment.
window1.ui defines maximumSize for tableWidget twice (first width=500, then width=16777215). In Qt Designer XML, the later property wins, so the 500px cap is effectively ignored and it’s unclear which behavior is intended. Remove the duplicate and keep a single maximumSize value.
| self.tableWidget.setSizePolicy(sizePolicy) | ||
| self.tableWidget.setMinimumSize(QtCore.QSize(225, 0)) | ||
| self.tableWidget.setMaximumSize(QtCore.QSize(500, 16777215)) | ||
| self.tableWidget.setMaximumSize(QtCore.QSize(16777215, 16777215)) |
There was a problem hiding this comment.
window1.py sets tableWidget maximum size twice in a row. The second call (16777215, 16777215) overrides the intended 500px width cap from the first call, so the new constraint has no effect. Remove the redundant call or keep only the desired maximum size.
| self.tableWidget.setMaximumSize(QtCore.QSize(16777215, 16777215)) |
| def resizeEvent(self, a0: QResizeEvent | None) -> None: | ||
| if a0 is None: | ||
| return | ||
| event = a0 | ||
| if self.scaleFactor and not self.scrollArea.widgetResizable(): | ||
| self.zoomToFit() |
There was a problem hiding this comment.
resizeEvent currently calls zoomToFit() whenever scaleFactor is set and scrollArea.widgetResizable() is false. This will also trigger after zoomTo1_1() (scaleFactor=1.0, widgetResizable=False) and after manual zoom in/out, so resizing the window will unexpectedly snap back to “fit”. Track an explicit “zoom-to-fit active” flag/state and only auto-fit on resize when that mode is enabled.
| # Extract column names from first row if it looks like headers | ||
| first_row = rows[0] | ||
| if len(first_row) >= 2 and first_row[0] != "": | ||
| # Assume first row contains headers | ||
| for col_name in first_row[1:]: | ||
| if col_name and col_name not in self.column_names: | ||
| self.column_names.append(col_name) | ||
|
|
||
| self.listlocation = len(rows) - 1 | ||
| for row_idx, rowdata in enumerate(rows): | ||
| if not rowdata: | ||
| continue | ||
| self.filelist.append(rowdata[0]) | ||
| num_cols = len(self.column_names) | ||
| for column in range(num_cols): |
There was a problem hiding this comment.
loadCSV() treats the first row as column headers whenever first_row[0] != "", then still iterates over that row as data and appends rowdata[0] into filelist. For typical CSVs where the first cell is a filename/path, this mis-detects headers and causes the first file to be treated as header text, and/or attempts to label.load() a non-file string. Consider detecting headers explicitly (e.g., first cell equals "File") and, when headers are present, skip the header row when populating filelist/table rows.
| self.tableWidget.setRowCount(len(rows)) | ||
| self.filelist = [] | ||
| self.column_names = ["File"] | ||
|
|
||
| # Extract column names from first row if it looks like headers | ||
| first_row = rows[0] | ||
| if len(first_row) >= 2 and first_row[0] != "": | ||
| # Assume first row contains headers | ||
| for col_name in first_row[1:]: | ||
| if col_name and col_name not in self.column_names: | ||
| self.column_names.append(col_name) | ||
|
|
||
| self.listlocation = len(rows) - 1 | ||
| for row_idx, rowdata in enumerate(rows): | ||
| if not rowdata: | ||
| continue | ||
| self.filelist.append(rowdata[0]) | ||
| num_cols = len(self.column_names) | ||
| for column in range(num_cols): | ||
| val = rowdata[column] if len(rowdata) > column else "" | ||
| item = QTableWidgetItem(val) | ||
| self.tableWidget.setItem(row_idx, column, item) | ||
|
|
||
| # Find first unrated row | ||
| for i in range(1, min(len(self.column_names), len(rowdata))): | ||
| if ( | ||
| i < len(rowdata) | ||
| and rowdata[i] == "" | ||
| and row_idx < self.listlocation | ||
| ): | ||
| self.listlocation = row_idx | ||
| break | ||
|
|
||
| self.tableWidget.setHorizontalHeaderLabels(self.column_names) | ||
| self.tableWidget.resizeColumnsToContents() |
There was a problem hiding this comment.
loadCSV() builds self.column_names but never updates tableWidget’s column count to match. If the CSV contains more (or fewer) rating columns than the default 3, setItem() and setHorizontalHeaderLabels() will not align with the actual table structure (and may fail for out-of-range columns). Set tableWidget.setColumnCount(len(self.column_names)) (and adjust after header parsing) before filling cells/setting headers.
| def showColumnContextMenu(self, pos): | ||
| header = self.tableWidget.horizontalHeader() | ||
|
|
||
| if header.underMouse(): | ||
| local_col = header.logicalIndexAt(pos) | ||
| header_pos = header.mapToGlobal(pos) | ||
| else: | ||
| local_col = self.tableWidget.columnAt(pos.x()) | ||
| header_pos = header.mapToGlobal( | ||
| self.tableWidget.viewport().mapFromGlobal(pos) | ||
| ) | ||
|
|
||
| if local_col == -1: | ||
| return | ||
|
|
||
| menu = QMenu(self) | ||
|
|
||
| if local_col > 0: | ||
| add_action = menu.addAction("Add Column") # type: ignore[assignment] | ||
| add_action.triggered.connect(self.addColumn) # type: ignore[union-attr] | ||
|
|
||
| rename_action = menu.addAction("Rename Column") # type: ignore[assignment] | ||
| rename_action.triggered.connect(self.renameColumn) # type: ignore[union-attr] | ||
|
|
||
| remove_action = menu.addAction("Remove Column") # type: ignore[assignment] | ||
| remove_action.triggered.connect(self.removeColumn) # type: ignore[union-attr] | ||
|
|
There was a problem hiding this comment.
showColumnContextMenu() computes local_col based on the right-click position, but the triggered actions call renameColumn()/removeColumn(), which operate on tableWidget.currentColumn(). If the user right-clicks a header without selecting a cell in that column first, rename/remove may apply to the wrong column. Pass local_col through to the handlers (e.g., via a lambda/partial) or set the current column/selection before showing the menu.
| from PyQt5.QtCore import QSize, Qt, QEvent | ||
| from PyQt5.QtGui import ( | ||
| QFont, | ||
| QPalette, | ||
| QPixmap, | ||
| QImage, | ||
| QMovie, | ||
| QKeyEvent, | ||
| QWheelEvent, | ||
| QResizeEvent, | ||
| ) | ||
| from PyQt5.QtWidgets import ( | ||
| QApplication, | ||
| QMainWindow, | ||
| QWidget, | ||
| QVBoxLayout, | ||
| QHBoxLayout, | ||
| QGridLayout, | ||
| QLabel, | ||
| QPushButton, | ||
| QLineEdit, | ||
| QTextEdit, | ||
| QTableWidget, | ||
| QTableWidgetItem, | ||
| QHeaderView, | ||
| QScrollArea, | ||
| QSplitter, | ||
| QFileDialog, | ||
| QInputDialog, | ||
| QMessageBox, | ||
| QMenu, | ||
| QMenuBar, | ||
| QStatusBar, | ||
| QAbstractItemView, | ||
| QDialog, | ||
| QAction, | ||
| ) |
There was a problem hiding this comment.
Several newly listed Qt imports (e.g., QEvent, QFont, QMenuBar, QStatusBar) appear unused in this file, which makes future maintenance harder and can confuse static analysis. Consider removing unused imports or limiting the import list to the classes actually referenced in PyQC.py.
|
|
||
| ## Dependencies | ||
|
|
||
| - Python 3.14 |
There was a problem hiding this comment.
AGENTS.md states a dependency on “Python 3.14”, but pyproject.toml and uv.lock declare requires-python = ">=3.8". Please align the documentation with the actual supported Python versions (or update pyproject.toml/lock/config if 3.14 is truly required).
| - Python 3.14 | |
| - Python >= 3.8 |
There was a problem hiding this comment.
Actionable comments posted: 5
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
PyQC.py (1)
391-404:⚠️ Potential issue | 🔴 CriticalSave duplicates the File column in CSV output.
At Line 397,
rowdatais initialized withself.filelist[row], then Lines 398-403 iterate over ALL columns including column 0 (File). This writes the file path twice to each CSV row.🐛 Proposed fix to skip column 0 when iterating
if self.path: with open(self.path, "w", newline="") as f: writer = csv.writer(f) for row in range(self.tableWidget.rowCount()): rowdata = [self.filelist[row]] - for column in range(self.tableWidget.columnCount()): + for column in range(1, self.tableWidget.columnCount()): item = self.tableWidget.item(row, column) if item is not None: rowdata.append(item.text()) else: rowdata.append("") writer.writerow(rowdata)Apply the same fix to
Savemethod at Line 412.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@PyQC.py` around lines 391 - 404, The CSV output duplicates the File column because SaveAs initializes rowdata with self.filelist[row] then iterates over all columns (including column 0); update the SaveAs method to skip column 0 when building rowdata (start the inner loop from column 1) so the file path isn't added twice, and apply the identical change to the Save method to keep behavior consistent; locate methods SaveAs and Save and modify the loop over self.tableWidget.columnCount() to begin at 1 instead of 0.
🧹 Nitpick comments (1)
window1.py (1)
12-12: Wildcard import is intentional per documented codegen workflow.Static analysis flags this as potentially problematic (F403, F405), but per AGENTS.md,
from image_widget import *is a required post-generation edit to integrateSaneDefaultsImageLabel. The current approach works but could be improved.💡 Optional: Use explicit import for clarity
-from image_widget import * +from image_widget import SaneDefaultsImageLabelThis would satisfy static analysis tools while maintaining the required functionality. Update AGENTS.md codegen instructions accordingly.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@window1.py` at line 12, Replace the wildcard import to an explicit import to satisfy linters while preserving the required SaneDefaultsImageLabel integration: change the current `from image_widget import *` usage so it explicitly imports SaneDefaultsImageLabel (and any other needed symbols) in the same location, and update AGENTS.md codegen instructions to instruct generated code to use `from image_widget import SaneDefaultsImageLabel` instead of a wildcard import.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@AGENTS.md`:
- Line 41: The README entry listing "Python 3.14" is incorrect (that version
isn't released); update the AGENTS.md line that currently reads "Python 3.14" to
the correct supported interpreter version (e.g., "Python 3.11" or "Python 3.12")
after verifying project compatibility, and ensure any related tooling/docs
mention the same version string to keep them consistent.
In `@PyQC.py`:
- Around line 428-432: The context-menu position calculation is wrong when
clicking the table body because pos is already in the table widget's coordinate
space; fix the computation in the else branch by converting pos to header/global
coordinates correctly: use the table widget's viewport.mapToGlobal or
header.mapToGlobal with a point derived from pos (not
viewport.mapFromGlobal(pos)). Update the logic around local_col, header_pos, and
the header.mapToGlobal/viewport mapping so header_pos is computed from a global
point obtained via self.tableWidget.viewport().mapToGlobal(pos) (or equivalent
correct conversion) before passing it to header.mapToGlobal.
- Around line 224-229: The resizeEvent currently calls zoomToFit whenever
scaleFactor is set and the scrollArea isn't widgetResizable, which overwrites
manual/1:1 zooms; introduce a zoomMode attribute (e.g., self.zoomMode = "fit" |
"manual") and update it wherever zoomToFit(), setScaleFactor(), or the
1:1/manual zoom actions occur, then change resizeEvent to call self.zoomToFit()
only when self.zoomMode == "fit" (leave behavior unchanged otherwise); ensure
zoomMode defaults to a sensible value and is updated in methods that change zoom
so manual zooms persist across window resizes.
- Around line 302-329: The first CSV header row (first_row) is being appended to
self.filelist and rendered into self.tableWidget after you populate
self.column_names; change the data-processing loop to skip the header row when
headers were detected (i.e., start iterating rows from index 1 instead of 0 when
first_row was used as headers), adjust how self.listlocation is
initialized/updated so it accounts for skipping the header, and ensure indexing
when creating QTableWidgetItem and checking unrated cells still references the
correct row indices (use the same header-detection flag or check first_row
presence to decide whether to start from 1 or 0 for the main for row_idx,
rowdata in enumerate(rows) loop that appends to self.filelist and sets table
items).
In `@window1.ui`:
- Around line 52-63: Remove the duplicate maximumSize property that overrides
the intended width cap: locate the two consecutive <property name="maximumSize">
blocks and delete the second block that sets width and height to 16777215 so the
first maximumSize with <width>500</width> remains effective; ensure only one
maximumSize property remains for the widget.
---
Outside diff comments:
In `@PyQC.py`:
- Around line 391-404: The CSV output duplicates the File column because SaveAs
initializes rowdata with self.filelist[row] then iterates over all columns
(including column 0); update the SaveAs method to skip column 0 when building
rowdata (start the inner loop from column 1) so the file path isn't added twice,
and apply the identical change to the Save method to keep behavior consistent;
locate methods SaveAs and Save and modify the loop over
self.tableWidget.columnCount() to begin at 1 instead of 0.
---
Nitpick comments:
In `@window1.py`:
- Line 12: Replace the wildcard import to an explicit import to satisfy linters
while preserving the required SaneDefaultsImageLabel integration: change the
current `from image_widget import *` usage so it explicitly imports
SaneDefaultsImageLabel (and any other needed symbols) in the same location, and
update AGENTS.md codegen instructions to instruct generated code to use `from
image_widget import SaneDefaultsImageLabel` instead of a wildcard import.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 57b7a83d-5f8e-4d5b-b659-8b39dd221d43
⛔ Files ignored due to path filters (1)
uv.lockis excluded by!**/*.lock
📒 Files selected for processing (4)
AGENTS.mdPyQC.pywindow1.pywindow1.ui
|
|
||
| ## Dependencies | ||
|
|
||
| - Python 3.14 |
There was a problem hiding this comment.
Verify the Python version requirement.
Python 3.14 is not yet released. This appears to be a typo—did you mean Python 3.11 or 3.12?
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@AGENTS.md` at line 41, The README entry listing "Python 3.14" is incorrect
(that version isn't released); update the AGENTS.md line that currently reads
"Python 3.14" to the correct supported interpreter version (e.g., "Python 3.11"
or "Python 3.12") after verifying project compatibility, and ensure any related
tooling/docs mention the same version string to keep them consistent.
| def resizeEvent(self, a0: QResizeEvent | None) -> None: | ||
| if a0 is None: | ||
| return | ||
| event = a0 | ||
| if self.scaleFactor and not self.scrollArea.widgetResizable(): | ||
| self.zoomToFit() |
There was a problem hiding this comment.
Resize behavior may not match user expectations.
The current logic triggers zoomToFit() on any resize when scaleFactor is set and widgetResizable() is False. This means after using "Zoom 1:1" or manual zoom in/out, resizing the window will override the zoom level and fit to window.
Consider tracking the zoom mode explicitly (e.g., self.zoomMode = "fit" vs "manual") so that only "Zoom to Fit" mode triggers auto-fit on resize, while 1:1 or manual zooms are preserved.
💡 Suggested approach
self.scaleFactor = None
self.insert_column = 1
self.column_names = ["File", "QC_Raw", "QC_Pre"]
+ self.zoomMode = "fit" # "fit" or "manual" def zoomTo1_1(self):
if not self.label.content or self.label.content.size().width() == 0:
return
self.scrollArea.setWidgetResizable(False)
self.scaleFactor = 1.0
+ self.zoomMode = "manual"
self.label.resize(self.label.content.size())
def zoomToFit(self):
if not self.label.content or self.label.content.size().width() == 0:
return
content_size = self.label.content.size()
viewport_size = self.scrollArea.viewport().size()
scale_width = viewport_size.width() / content_size.width()
scale_height = viewport_size.height() / content_size.height()
self.scaleFactor = min(scale_width, scale_height)
self.scrollArea.setWidgetResizable(False)
+ self.zoomMode = "fit"
self.label.resize(self.scaleFactor * content_size)
def resizeEvent(self, a0: QResizeEvent | None) -> None:
if a0 is None:
return
- if self.scaleFactor and not self.scrollArea.widgetResizable():
+ if self.zoomMode == "fit" and self.scaleFactor:
self.zoomToFit()🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@PyQC.py` around lines 224 - 229, The resizeEvent currently calls zoomToFit
whenever scaleFactor is set and the scrollArea isn't widgetResizable, which
overwrites manual/1:1 zooms; introduce a zoomMode attribute (e.g., self.zoomMode
= "fit" | "manual") and update it wherever zoomToFit(), setScaleFactor(), or the
1:1/manual zoom actions occur, then change resizeEvent to call self.zoomToFit()
only when self.zoomMode == "fit" (leave behavior unchanged otherwise); ensure
zoomMode defaults to a sensible value and is updated in methods that change zoom
so manual zooms persist across window resizes.
| # Extract column names from first row if it looks like headers | ||
| first_row = rows[0] | ||
| if len(first_row) >= 2 and first_row[0] != "": | ||
| # Assume first row contains headers | ||
| for col_name in first_row[1:]: | ||
| if col_name and col_name not in self.column_names: | ||
| self.column_names.append(col_name) | ||
|
|
||
| self.listlocation = len(rows) - 1 | ||
| for row_idx, rowdata in enumerate(rows): | ||
| if not rowdata: | ||
| continue | ||
| self.filelist.append(rowdata[0]) | ||
| num_cols = len(self.column_names) | ||
| for column in range(num_cols): | ||
| val = rowdata[column] if len(rowdata) > column else "" | ||
| item = QTableWidgetItem(val) | ||
| self.tableWidget.setItem(row_idx, column, item) | ||
|
|
||
| # Find first unrated row | ||
| for i in range(1, min(len(self.column_names), len(rowdata))): | ||
| if ( | ||
| i < len(rowdata) | ||
| and rowdata[i] == "" | ||
| and row_idx < self.listlocation | ||
| ): | ||
| self.listlocation = row_idx | ||
| break |
There was a problem hiding this comment.
CSV header row is incorrectly treated as file data.
When the first row contains headers (detected at Line 304), the code extracts column names but still processes that row as data at Lines 311-329. This adds the header text (e.g., "File") to self.filelist and creates a table row for it, causing file load errors.
🐛 Proposed fix to skip header row when processing data
# Extract column names from first row if it looks like headers
first_row = rows[0]
- if len(first_row) >= 2 and first_row[0] != "":
+ has_headers = len(first_row) >= 2 and not os.path.exists(first_row[0])
+ if has_headers:
# Assume first row contains headers
for col_name in first_row[1:]:
if col_name and col_name not in self.column_names:
self.column_names.append(col_name)
+ data_rows = rows[1:]
+ else:
+ data_rows = rows
- self.listlocation = len(rows) - 1
- for row_idx, rowdata in enumerate(rows):
+ self.tableWidget.setRowCount(len(data_rows))
+ self.listlocation = len(data_rows) - 1
+ for row_idx, rowdata in enumerate(data_rows):🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@PyQC.py` around lines 302 - 329, The first CSV header row (first_row) is
being appended to self.filelist and rendered into self.tableWidget after you
populate self.column_names; change the data-processing loop to skip the header
row when headers were detected (i.e., start iterating rows from index 1 instead
of 0 when first_row was used as headers), adjust how self.listlocation is
initialized/updated so it accounts for skipping the header, and ensure indexing
when creating QTableWidgetItem and checking unrated cells still references the
correct row indices (use the same header-detection flag or check first_row
presence to decide whether to start from 1 or 0 for the main for row_idx,
rowdata in enumerate(rows) loop that appends to self.filelist and sets table
items).
| else: | ||
| local_col = self.tableWidget.columnAt(pos.x()) | ||
| header_pos = header.mapToGlobal( | ||
| self.tableWidget.viewport().mapFromGlobal(pos) | ||
| ) |
There was a problem hiding this comment.
Context menu position calculation is incorrect for table body clicks.
When the click is on the table body (not header), pos is already relative to the table widget, but Line 431-432 uses self.tableWidget.viewport().mapFromGlobal(pos) which treats pos as a global coordinate. This will show the menu in the wrong location.
🐛 Proposed fix
if header.underMouse():
local_col = header.logicalIndexAt(pos)
header_pos = header.mapToGlobal(pos)
else:
local_col = self.tableWidget.columnAt(pos.x())
- header_pos = header.mapToGlobal(
- self.tableWidget.viewport().mapFromGlobal(pos)
- )
+ header_pos = self.tableWidget.mapToGlobal(pos)📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| else: | |
| local_col = self.tableWidget.columnAt(pos.x()) | |
| header_pos = header.mapToGlobal( | |
| self.tableWidget.viewport().mapFromGlobal(pos) | |
| ) | |
| else: | |
| local_col = self.tableWidget.columnAt(pos.x()) | |
| header_pos = self.tableWidget.mapToGlobal(pos) |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@PyQC.py` around lines 428 - 432, The context-menu position calculation is
wrong when clicking the table body because pos is already in the table widget's
coordinate space; fix the computation in the else branch by converting pos to
header/global coordinates correctly: use the table widget's viewport.mapToGlobal
or header.mapToGlobal with a point derived from pos (not
viewport.mapFromGlobal(pos)). Update the logic around local_col, header_pos, and
the header.mapToGlobal/viewport mapping so header_pos is computed from a global
point obtained via self.tableWidget.viewport().mapToGlobal(pos) (or equivalent
correct conversion) before passing it to header.mapToGlobal.
| <property name="maximumSize"> | ||
| <size> | ||
| <width>500</width> | ||
| <height>16777215</height> | ||
| </size> | ||
| </property> | ||
| <property name="maximumSize"> | ||
| <size> | ||
| <width>16777215</width> | ||
| <height>16777215</height> | ||
| </size> | ||
| </property> |
There was a problem hiding this comment.
Duplicate maximumSize property; second definition overrides the first.
Lines 52-57 set maximumSize to width 500, but Lines 58-63 immediately override it with an unbounded size (16777215). The width constraint of 500 will not be applied.
If the intent is to cap the table width at 500px, remove the second maximumSize definition.
🐛 Proposed fix to remove duplicate property
<property name="maximumSize">
<size>
<width>500</width>
<height>16777215</height>
</size>
</property>
- <property name="maximumSize">
- <size>
- <width>16777215</width>
- <height>16777215</height>
- </size>
- </property>📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| <property name="maximumSize"> | |
| <size> | |
| <width>500</width> | |
| <height>16777215</height> | |
| </size> | |
| </property> | |
| <property name="maximumSize"> | |
| <size> | |
| <width>16777215</width> | |
| <height>16777215</height> | |
| </size> | |
| </property> | |
| <property name="maximumSize"> | |
| <size> | |
| <width>500</width> | |
| <height>16777215</height> | |
| </size> | |
| </property> |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@window1.ui` around lines 52 - 63, Remove the duplicate maximumSize property
that overrides the intended width cap: locate the two consecutive <property
name="maximumSize"> blocks and delete the second block that sets width and
height to 16777215 so the first maximumSize with <width>500</width> remains
effective; ensure only one maximumSize property remains for the widget.
Summary by CodeRabbit
New Features
Documentation