ASSISTANT
To ensure that the plus and minus buttons are positioned vertically at the center of the row that the mouse is hovering over, we need to adjust how the vertical position (`y_pos`) is calculated. We need to base this calculation on the dimensions of the visual rectangle representing the hovered row. Here's how you can adjust the code:
### Step-by-Step Fix:
1. **Find the Correct Rectangle Dimension**: Use `visualRect()` to get the rectangle of the hovered index.
2. **Center the Buttons Vertically**: Calculate the `y_pos` by taking the top of the rectangle and adding half the difference between the rectangle's height and the button's height.
Here's the updated code snippet for the `update_buttons_position` function with this adjustment:
```python
def update_buttons_position(self, table, pos):
index = table.indexAt(pos)
if index.isValid():
row_index = index.row()
self.current_row_id = table.model().index(row_index, 0).data() # Assuming the first column has unique IDs
rect = table.visualRect(index)
# Center the buttons vertically within the row
y_pos = rect.top() + (rect.height() - self.plus_button.height()) // 2
# Calculate x-position for centering buttons horizontally within the button bar
button_spacing = 5
button_bar_center = self.button_bar.width() // 2
combined_button_widths = self.plus_button.width() + self.minus_button.width() + button_spacing
first_button_x = button_bar_center - (combined_button_widths // 2)
self.plus_button.move(first_button_x, y_pos)
self.minus_button.move(first_button_x + self.plus_button.width() + button_spacing, y_pos)
self.plus_button.setVisible(True)
self.minus_button.setVisible(True)
else:
self.plus_button.setVisible(False)
self.minus_button.setVisible(False)
self.current_row_id = None
```
### Full Code (for Reference):
Ensure the above logic is integrated correctly in the full program:
```python
import sys
from PySide6.QtWidgets import (
QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout,
QPushButton, QTableView, QFrame
)
from PySide6.QtGui import QStandardItemModel, QStandardItem
from PySide6.QtCore import QEvent, Qt, QPoint
import sqlite3
def run_query(query, parameters=()):
with sqlite3.connect('media.db') as conn:
cursor = conn.cursor()
result = cursor.execute(query, parameters)
if query.strip().lower().startswith("select"):
return result.fetchall()
conn.commit()
def create_tables():
create_movies_table_sql = '''
CREATE TABLE IF NOT EXISTS movies (
id INTEGER PRIMARY KEY AUTOINCREMENT,
movie TEXT,
year INTEGER,
present BOOLEAN,
watched BOOLEAN,
notes TEXT
);
'''
create_series_table_sql = '''
CREATE TABLE IF NOT EXISTS series (
id INTEGER PRIMARY KEY AUTOINCREMENT,
series TEXT,
seasons TEXT,
year TEXT,
present BOOLEAN,
seasons_present TEXT,
complete BOOLEAN,
watched BOOLEAN,
seasons_seen TEXT,
notes TEXT
);
'''
run_query(create_movies_table_sql)
run_query(create_series_table_sql)
class MediaTracker(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("Movies and Series Tracker")
self.setGeometry(200, 100, 1000, 600)
self.main_widget = QWidget(self)
self.setCentralWidget(self.main_widget)
self.main_layout = QHBoxLayout(self.main_widget)
# Sidebar with navigation buttons
self.sidebar_layout = QVBoxLayout()
self.main_layout.addLayout(self.sidebar_layout)
self.movies_button = QPushButton("Movies")
self.movies_button.clicked.connect(self.show_movies)
self.sidebar_layout.addWidget(self.movies_button)
self.series_button = QPushButton("Series")
self.series_button.clicked.connect(self.show_series)
self.sidebar_layout.addWidget(self.series_button)
self.sidebar_layout.addStretch()
# Button bar area (spacer for aesthetics and logical separation)
self.button_bar = QFrame()
self.button_bar.setFixedWidth(50)
self.button_bar.setStyleSheet("background-color: white;")
self.main_layout.addWidget(self.button_bar)
# Content layout for the table
self.content_layout = QVBoxLayout()
self.main_layout.addLayout(self.content_layout)
self.setup_movie_table()
self.setup_series_table()
# '+' and '-' buttons for current row
self.plus_button = QPushButton("+", self.button_bar)
self.plus_button.setFixedSize(20, 20)
self.plus_button.setVisible(False)
self.plus_button.raise_()
self.plus_button.clicked.connect(self.add_entry)
self.minus_button = QPushButton("-", self.button_bar)
self.minus_button.setFixedSize(20, 20)
self.minus_button.setVisible(False)
self.minus_button.raise_()
self.minus_button.clicked.connect(self.delete_entry)
self.current_row_id = None # To track the current hovered row ID
self.load_data()
self.show_movies()
def setup_movie_table(self):
self.movies_model = QStandardItemModel()
self.movies_columns = ["Movie", "Year", "Present", "Watched", "Notes"]
self.movies_model.setHorizontalHeaderLabels(self.movies_columns)
self.movies_table = QTableView()
self.movies_table.setModel(self.movies_model)
self.movies_table.setVerticalScrollMode(QTableView.ScrollPerPixel)
self.movies_table.setMouseTracking(True)
self.movies_table.viewport().installEventFilter(self)
self.content_layout.addWidget(self.movies_table)
def setup_series_table(self):
self.series_model = QStandardItemModel()
self.series_columns = ["Series", "Seasons", "Year", "Present", "Seasons Present",
"Complete", "Watched", "Seasons Seen", "Notes"]
self.series_model.setHorizontalHeaderLabels(self.series_columns)
self.series_table = QTableView()
self.series_table.setModel(self.series_model)
self.series_table.setVerticalScrollMode(QTableView.ScrollPerPixel)
self.series_table.setMouseTracking(True)
self.series_table.viewport().installEventFilter(self)
def load_data(self):
if self.movies_table.isVisible():
self.load_movie_data()
else:
self.load_series_data()
def load_movie_data(self):
self.movies_model.removeRows(0, self.movies_model.rowCount())
movies_data = run_query('SELECT * FROM movies')
for row in movies_data:
items = [QStandardItem(str(data)) if data is not None else QStandardItem("") for data in row[1:]]
self.movies_model.appendRow(items)
def load_series_data(self):
self.series_model.removeRows(0, self.series_model.rowCount())
series_data = run_query('SELECT * FROM series')
for row in series_data:
items = [QStandardItem(str(data)) if data is not None else QStandardItem("") for data in row[1:]]
self.series_model.appendRow(items)
def show_movies(self):
self.clear_content()
self.content_layout.addWidget(self.movies_table)
self.load_movie_data()
def show_series(self):
self.clear_content()
self.content_layout.addWidget(self.series_table)
self.load_series_data()
def add_entry(self):
if self.movies_table.isVisible():
run_query("INSERT INTO movies (movie, year, present, watched, notes) VALUES (?, ?, ?, ?, ?)",
('', None, None, None, ''))
self.load_movie_data()
elif self.series_table.isVisible():
run_query("INSERT INTO series (series, seasons, year, present, seasons_present, complete, watched, seasons_seen, notes) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)",
('', '', '', None, '', None, None, '', ''))
self.load_series_data()
def delete_entry(self):
if self.current_row_id is not None:
table = self.movies_table if self.movies_table.isVisible() else self.series_table
if table is self.movies_table:
run_query("DELETE FROM movies WHERE id = ?", (self.current_row_id,))
self.load_movie_data()
elif table is self.series_table:
run_query("DELETE FROM series WHERE id = ?", (self.current_row_id,))
self.load_series_data()
def clear_content(self):
# Remove current content
for i in reversed(range(self.content_layout.count())):
widget_to_remove = self.content_layout.itemAt(i).widget()
self.content_layout.removeWidget(widget_to_remove)
if widget_to_remove is not None:
widget_to_remove.setParent(None)
def eventFilter(self, source, event):
if event.type() == QEvent.Type.MouseMove:
table = self.movies_table if self.movies_table.isVisible() else self.series_table
if source is table.viewport():
self.update_buttons_position(table, event.position().toPoint())
return super(MediaTracker, self).eventFilter(source, event)
def update_buttons_position(self, table, pos):
index = table.indexAt(pos)
if index.isValid():
row_index = index.row()
self.current_row_id = table.model().index(row_index, 0).data() # Assuming the first column has unique IDs
rect = table.visualRect(index)
# Center the buttons vertically within the row
y_pos = rect.top() + (rect.height() - self.plus_button.height()) // 2
# Calculate x-position for centering buttons horizontally within the button bar
button_spacing = 5
button_bar_center = self.button_bar.width() // 2
combined_button_widths = self.plus_button.width() + self.minus_button.width() + button_spacing
first_button_x = button_bar_center - (combined_button_widths // 2)
self.plus_button.move(first_button_x, y_pos)
self.minus_button.move(first_button_x + self.plus_button.width() + button_spacing, y_pos)
self.plus_button.setVisible(True)
self.minus_button.setVisible(True)
else:
self.plus_button.setVisible(False)
self.minus_button.setVisible(False)
self.current_row_id = None
if __name__ == "__main__":
app = QApplication(sys.argv)
create_tables()
tracker = MediaTracker()
tracker.show()
sys.exit(app.exec())
```
In this updated code, the vertical position `y_pos` of the buttons is calculated to be the middle of the height of the hovered row. This should correctly position both the plus and minus buttons in the middle of each hovered row, ensuring visual alignment.