This commit is contained in:
parent
0de9beec8e
commit
6bc851b03c
|
|
@ -1494,30 +1494,29 @@ class _MetricRow(QWidget):
|
||||||
self.val_lbl.setStyleSheet(f"color:{c}; font-size:12px; font-family:'Consolas';")
|
self.val_lbl.setStyleSheet(f"color:{c}; font-size:12px; font-family:'Consolas';")
|
||||||
|
|
||||||
|
|
||||||
def _make_scroll_tab(fields):
|
def _make_grid_tab(fields, cols=2):
|
||||||
"""Return (QWidget tab, dict of key->_MetricRow)."""
|
"""Return (QWidget tab, dict of key->MetricCell) using 2-col metric card grid."""
|
||||||
tab = QWidget()
|
tab = QWidget()
|
||||||
scroll = QScrollArea()
|
scroll = QScrollArea()
|
||||||
scroll.setWidgetResizable(True)
|
scroll.setWidgetResizable(True)
|
||||||
scroll.setFrameShape(QFrame.NoFrame)
|
scroll.setFrameShape(QFrame.NoFrame)
|
||||||
inner = QWidget()
|
inner = QWidget()
|
||||||
lay = QVBoxLayout(inner)
|
lay = QGridLayout(inner)
|
||||||
lay.setContentsMargins(0, 4, 0, 4)
|
lay.setContentsMargins(10, 10, 10, 10)
|
||||||
lay.setSpacing(0)
|
lay.setSpacing(6)
|
||||||
rows = {}
|
cells = {}
|
||||||
for label, key in fields:
|
for i, (label, key) in enumerate(fields):
|
||||||
row_w = _MetricRow(label, key)
|
tip = _METRIC_TOOLTIPS.get(label, "")
|
||||||
rows[key] = row_w
|
cell = MetricCell(label, key, tip)
|
||||||
lay.addWidget(row_w)
|
cells[key] = cell
|
||||||
sep = QFrame(); sep.setFixedHeight(1)
|
lay.addWidget(cell, i // cols, i % cols)
|
||||||
sep.setStyleSheet(f"background:{_C['border']};")
|
# stretch the last row so cards stay top-aligned
|
||||||
lay.addWidget(sep)
|
lay.setRowStretch((len(fields) - 1) // cols + 1, 1)
|
||||||
lay.addStretch()
|
|
||||||
scroll.setWidget(inner)
|
scroll.setWidget(inner)
|
||||||
outer = QVBoxLayout(tab)
|
outer = QVBoxLayout(tab)
|
||||||
outer.setContentsMargins(0, 0, 0, 0)
|
outer.setContentsMargins(0, 0, 0, 0)
|
||||||
outer.addWidget(scroll)
|
outer.addWidget(scroll)
|
||||||
return tab, rows
|
return tab, cells
|
||||||
|
|
||||||
|
|
||||||
class DetailPanel(QWidget):
|
class DetailPanel(QWidget):
|
||||||
|
|
@ -1560,43 +1559,41 @@ class DetailPanel(QWidget):
|
||||||
self._tabs.addTab(self._score_tab, "Scores")
|
self._tabs.addTab(self._score_tab, "Scores")
|
||||||
|
|
||||||
# Valuation
|
# Valuation
|
||||||
t, rows = _make_scroll_tab(_VAL_FIELDS)
|
t, cells = _make_grid_tab(_VAL_FIELDS)
|
||||||
self._all_rows.update(rows)
|
self._all_rows.update(cells)
|
||||||
self._tabs.addTab(t, "Valuation")
|
self._tabs.addTab(t, "Valuation")
|
||||||
|
|
||||||
# Growth
|
# Growth
|
||||||
t, rows = _make_scroll_tab(_GROWTH_FIELDS)
|
t, cells = _make_grid_tab(_GROWTH_FIELDS)
|
||||||
self._all_rows.update(rows)
|
self._all_rows.update(cells)
|
||||||
self._tabs.addTab(t, "Growth")
|
self._tabs.addTab(t, "Growth")
|
||||||
|
|
||||||
# Momentum
|
# Momentum
|
||||||
t, rows = _make_scroll_tab(_MOM_FIELDS)
|
t, cells = _make_grid_tab(_MOM_FIELDS)
|
||||||
self._all_rows.update(rows)
|
self._all_rows.update(cells)
|
||||||
self._tabs.addTab(t, "Momentum")
|
self._tabs.addTab(t, "Momentum")
|
||||||
|
|
||||||
# Quality & Profit
|
# Quality & Profit
|
||||||
t, rows = _make_scroll_tab(_QUAL_FIELDS)
|
t, cells = _make_grid_tab(_QUAL_FIELDS)
|
||||||
self._all_rows.update(rows)
|
self._all_rows.update(cells)
|
||||||
self._tabs.addTab(t, "Quality & Profit")
|
self._tabs.addTab(t, "Quality & Profit")
|
||||||
|
|
||||||
# Analyst tab (metrics + commentary)
|
# Analyst tab (metric grid + commentary)
|
||||||
analyst_tab = QWidget()
|
analyst_tab = QWidget()
|
||||||
al = QVBoxLayout(analyst_tab)
|
al = QVBoxLayout(analyst_tab)
|
||||||
al.setContentsMargins(0, 0, 0, 0)
|
al.setContentsMargins(0, 0, 0, 0)
|
||||||
al.setSpacing(0)
|
al.setSpacing(0)
|
||||||
# Metrics in a small scrollable area
|
# Metrics as a 2-col grid
|
||||||
anlst_inner = QWidget()
|
anlst_grid_w = QWidget()
|
||||||
anlst_lay = QVBoxLayout(anlst_inner)
|
anlst_grid_lay = QGridLayout(anlst_grid_w)
|
||||||
anlst_lay.setContentsMargins(0, 4, 0, 4)
|
anlst_grid_lay.setContentsMargins(10, 10, 10, 6)
|
||||||
anlst_lay.setSpacing(0)
|
anlst_grid_lay.setSpacing(6)
|
||||||
for label, key in _ANLST_FIELDS:
|
for i, (label, key) in enumerate(_ANLST_FIELDS):
|
||||||
row_w = _MetricRow(label, key)
|
tip = _METRIC_TOOLTIPS.get(label, "")
|
||||||
self._all_rows[key] = row_w
|
cell = MetricCell(label, key, tip)
|
||||||
anlst_lay.addWidget(row_w)
|
self._all_rows[key] = cell
|
||||||
sep2 = QFrame(); sep2.setFixedHeight(1)
|
anlst_grid_lay.addWidget(cell, i // 2, i % 2)
|
||||||
sep2.setStyleSheet(f"background:{_C['border']};")
|
al.addWidget(anlst_grid_w)
|
||||||
anlst_lay.addWidget(sep2)
|
|
||||||
al.addWidget(anlst_inner)
|
|
||||||
|
|
||||||
hdiv = QFrame(); hdiv.setFixedHeight(1)
|
hdiv = QFrame(); hdiv.setFixedHeight(1)
|
||||||
hdiv.setStyleSheet(f"background:{_C['border']};")
|
hdiv.setStyleSheet(f"background:{_C['border']};")
|
||||||
|
|
@ -2044,6 +2041,7 @@ class ScreenerPage(QWidget):
|
||||||
self._run_btn.setEnabled(True)
|
self._run_btn.setEnabled(True)
|
||||||
self._stop_btn.setEnabled(False)
|
self._stop_btn.setEnabled(False)
|
||||||
self._progress.hide()
|
self._progress.hide()
|
||||||
|
QMessageBox.critical(self, "Screen Error", f"The screening run failed:\n\n{text}")
|
||||||
|
|
||||||
@Slot()
|
@Slot()
|
||||||
def _on_stopped(self):
|
def _on_stopped(self):
|
||||||
|
|
@ -2054,6 +2052,14 @@ class ScreenerPage(QWidget):
|
||||||
|
|
||||||
def _apply_filters(self):
|
def _apply_filters(self):
|
||||||
if self._df is None: return
|
if self._df is None: return
|
||||||
|
try:
|
||||||
|
self._apply_filters_inner()
|
||||||
|
except Exception as exc:
|
||||||
|
import traceback
|
||||||
|
QMessageBox.critical(self, "Display Error",
|
||||||
|
f"Failed to display results:\n\n{traceback.format_exc()}")
|
||||||
|
|
||||||
|
def _apply_filters_inner(self):
|
||||||
df = self._df
|
df = self._df
|
||||||
rule = _SECTOR_FILTER_MAP.get(self._sector_cb.currentText())
|
rule = _SECTOR_FILTER_MAP.get(self._sector_cb.currentText())
|
||||||
if rule:
|
if rule:
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ import requests
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
# Current app version — kept in sync by push_update.py before each build.
|
# Current app version — kept in sync by push_update.py before each build.
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
APP_VERSION = "1.4.3"
|
APP_VERSION = "1.4.4"
|
||||||
|
|
||||||
|
|
||||||
def _exe_dir() -> str:
|
def _exe_dir() -> str:
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue