my final form!!!
This commit is contained in:
384
Л3-В6/Программа/src/window.py
Normal file
384
Л3-В6/Программа/src/window.py
Normal file
@@ -0,0 +1,384 @@
|
||||
import sys
|
||||
from PyQt6.QtWidgets import (
|
||||
QMessageBox,
|
||||
QMainWindow,
|
||||
QLabel,
|
||||
QComboBox,
|
||||
QPushButton,
|
||||
QFormLayout,
|
||||
QWidget,
|
||||
QLineEdit,
|
||||
QHBoxLayout,
|
||||
QLayout,
|
||||
QApplication,
|
||||
)
|
||||
from PyQt6.QtCore import Qt
|
||||
import numpy as np
|
||||
|
||||
import task
|
||||
import algorithm
|
||||
import solution
|
||||
|
||||
|
||||
class DisplayField(QWidget):
|
||||
label_text: str
|
||||
|
||||
def __init__(self, parent, label_text="", text=""):
|
||||
super().__init__(parent)
|
||||
|
||||
self._layout = QHBoxLayout(self)
|
||||
self._layout.setContentsMargins(0, 0, 0, 0)
|
||||
|
||||
self.label_text = label_text
|
||||
self.text = QLabel(f"{self.label_text}{text}")
|
||||
self.text.setAlignment(Qt.AlignmentFlag.AlignLeft)
|
||||
|
||||
self._layout.addWidget(self.text)
|
||||
|
||||
def set_visible(self, visible):
|
||||
self.text.setVisible(visible)
|
||||
|
||||
def set_text(self, text):
|
||||
self.text.setText(f"{self.label_text}{text}")
|
||||
|
||||
|
||||
class InputField(QWidget):
|
||||
value: str
|
||||
change_func: callable = None
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
parent,
|
||||
label_text="",
|
||||
placeholder_text="",
|
||||
lineedit_text="",
|
||||
label_position="left",
|
||||
):
|
||||
super().__init__(parent)
|
||||
|
||||
self._layout = QHBoxLayout(self)
|
||||
self._layout.setContentsMargins(0, 0, 0, 0)
|
||||
self.label = QLabel(label_text)
|
||||
self.lineedit = QLineEdit(lineedit_text)
|
||||
self.lineedit.setPlaceholderText(placeholder_text)
|
||||
self.lineedit.setMinimumWidth(50)
|
||||
|
||||
if label_position == "left":
|
||||
self._layout.addWidget(self.label)
|
||||
self._layout.addWidget(self.lineedit)
|
||||
elif label_position == "right":
|
||||
self._layout.addWidget(self.lineedit)
|
||||
self._layout.addWidget(self.label)
|
||||
elif label_position == "none":
|
||||
self._layout.addWidget(self.lineedit)
|
||||
|
||||
self.value = self.get_value()
|
||||
self.lineedit.textChanged.connect(self._on_change)
|
||||
|
||||
def get_value(self):
|
||||
return self.lineedit.text()
|
||||
|
||||
def set_value(self, value):
|
||||
self.lineedit.setText(value)
|
||||
|
||||
def on_change(self, func):
|
||||
self.change_func = func
|
||||
|
||||
def _on_change(self):
|
||||
if self.change_func:
|
||||
self.change_func(self)
|
||||
|
||||
self.value = self.get_value()
|
||||
|
||||
|
||||
def on_input_float_number(widget: InputField):
|
||||
try:
|
||||
str_value = widget.get_value()
|
||||
if not (str_value == "" or str_value == "-"):
|
||||
widget.value = str(float(str_value))
|
||||
except:
|
||||
widget.set_value(str(widget.value))
|
||||
|
||||
|
||||
def on_input_int_number(widget: InputField):
|
||||
try:
|
||||
str_value = widget.get_value()
|
||||
if not (str_value == "" or str_value == "-"):
|
||||
widget.value = str(int(str_value))
|
||||
except:
|
||||
widget.set_value(str(widget.value))
|
||||
|
||||
|
||||
class MatrixRowWidget(QWidget):
|
||||
x_inputs: list[InputField]
|
||||
b_input: InputField
|
||||
|
||||
def __init__(self, parent, i: int, n: int):
|
||||
super().__init__(parent)
|
||||
|
||||
self._layout = QHBoxLayout()
|
||||
self._layout.setContentsMargins(0, 0, 0, 0)
|
||||
self.x_inputs = []
|
||||
for j in range(n):
|
||||
inp = InputField(self, f"x{j + 1}", "", "0.0", "right")
|
||||
inp.lineedit.setAlignment(Qt.AlignmentFlag.AlignRight)
|
||||
self.x_inputs.append(inp)
|
||||
self._layout.addWidget(inp)
|
||||
if j != n - 1:
|
||||
self._layout.addWidget(QLabel(" + "))
|
||||
|
||||
self._layout.addWidget(QLabel(" = "))
|
||||
self.b_input = InputField(self, "", "", "0.0", "none")
|
||||
self.b_input.lineedit.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
||||
self._layout.addWidget(self.b_input)
|
||||
|
||||
self.setLayout(self._layout)
|
||||
|
||||
def get_value_x(self, i: int):
|
||||
return self.x_inputs[i].get_value()
|
||||
|
||||
def get_value_b(self):
|
||||
return self.b_input.get_value()
|
||||
|
||||
def on_change(self, func):
|
||||
for inp in self.x_inputs:
|
||||
inp.on_change(func)
|
||||
|
||||
self.b_input.on_change(func)
|
||||
|
||||
|
||||
class MatrixWidget(QWidget):
|
||||
rows: list[MatrixRowWidget]
|
||||
_layout: QFormLayout
|
||||
on_change_func = None
|
||||
|
||||
def __init__(self, parent, n: int):
|
||||
super().__init__(parent)
|
||||
|
||||
self._initialize()
|
||||
self._create(n)
|
||||
|
||||
def _initialize(self):
|
||||
self.rows = []
|
||||
self._layout = QFormLayout()
|
||||
self._layout.setContentsMargins(0, 0, 0, 0)
|
||||
|
||||
def _create(self, n: int):
|
||||
for i in range(n):
|
||||
self.rows.append(MatrixRowWidget(self, i, n))
|
||||
|
||||
for row in self.rows:
|
||||
self._layout.addRow(row)
|
||||
if self.on_change_func:
|
||||
row.on_change(self.on_change_func)
|
||||
|
||||
self.setLayout(self._layout)
|
||||
|
||||
def recreate(self, n: int):
|
||||
for row in self.rows:
|
||||
row.deleteLater()
|
||||
|
||||
self.rows = []
|
||||
self._create(n)
|
||||
|
||||
def set_value_x(self, i: int, j: int, value: float):
|
||||
self.rows[i].x_inputs[j].set_value(value)
|
||||
|
||||
def set_value_b(self, i: int, value: float):
|
||||
self.rows[i].b_input.set_value(value)
|
||||
|
||||
def get_value_x(self, i: int, j: int):
|
||||
return self.rows[i].get_value_x(j)
|
||||
|
||||
def get_value_b(self, i: int):
|
||||
return self.rows[i].get_value_b()
|
||||
|
||||
def on_change(self, func):
|
||||
self.on_change_func = func
|
||||
|
||||
for row in self.rows:
|
||||
if self.on_change_func:
|
||||
row.on_change(self.on_change_func)
|
||||
|
||||
|
||||
class MainWindow(QMainWindow):
|
||||
initialized = False
|
||||
|
||||
matrix_a: np.matrix
|
||||
matrix_b: np.matrix
|
||||
|
||||
det_display: DisplayField
|
||||
cond_display: DisplayField
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
self.setupUI()
|
||||
|
||||
self.initialized = True
|
||||
self.update_stats()
|
||||
|
||||
def setupUI(self):
|
||||
self.setWindowTitle("Лабораторная работа №3")
|
||||
self.central_widget = QWidget()
|
||||
self.setCentralWidget(self.central_widget)
|
||||
|
||||
layout = QFormLayout()
|
||||
|
||||
label1 = QLabel("Вариант 6", self)
|
||||
layout.addWidget(label1)
|
||||
|
||||
self.n_input = InputField(self, " n: ", "число строк", str(4), "left")
|
||||
self.n_input.on_change(lambda w: self.on_n_input_changed(w))
|
||||
layout.addWidget(self.n_input)
|
||||
|
||||
buttons_row = QWidget()
|
||||
buttons_row_layout = QHBoxLayout()
|
||||
buttons_row_layout.setContentsMargins(0, 0, 0, 0)
|
||||
|
||||
self.reset_button = QPushButton("Сбросить", self)
|
||||
self.reset_button.clicked.connect(self.on_reset_button_clicked)
|
||||
buttons_row_layout.addWidget(self.reset_button)
|
||||
|
||||
self.paste_button = QPushButton("Вставить", self)
|
||||
self.paste_button.clicked.connect(self.on_paste_button_clicked)
|
||||
buttons_row_layout.addWidget(self.paste_button)
|
||||
|
||||
buttons_row.setLayout(buttons_row_layout)
|
||||
layout.addWidget(buttons_row)
|
||||
|
||||
self.matrix = MatrixWidget(self, 4)
|
||||
self.matrix.on_change(lambda w: self.on_matrix_changed(w))
|
||||
self.set_matrix(task.A(), task.B())
|
||||
layout.addWidget(self.matrix)
|
||||
|
||||
self.det_display = DisplayField(self, "Определитель: ", "")
|
||||
layout.addWidget(self.det_display)
|
||||
|
||||
self.cond_display = DisplayField(self, "Число обусловленности: ", "")
|
||||
layout.addWidget(self.cond_display)
|
||||
|
||||
find_solution_button = QPushButton("Решить", self)
|
||||
find_solution_button.clicked.connect(self.on_find_solution_clicked)
|
||||
layout.addWidget(find_solution_button)
|
||||
|
||||
self.solution_display = DisplayField(self, "Решение: ", "")
|
||||
layout.addWidget(self.solution_display)
|
||||
self.solution_display.set_visible(False)
|
||||
|
||||
self.central_widget.setLayout(layout)
|
||||
|
||||
def on_find_solution_clicked(self):
|
||||
x = solution.iterative_method(self.matrix_a, self.matrix_b)
|
||||
|
||||
if x is None:
|
||||
self.solution_display.set_visible(True)
|
||||
self.solution_display.set_text("Нет решения")
|
||||
else:
|
||||
self.solution_display.set_visible(True)
|
||||
solution_text = "\n"
|
||||
for i in range(x.shape[0]):
|
||||
solution_text += f"x{i} = {x[i, 0]:.5f}"
|
||||
if i < x.shape[0] - 1:
|
||||
solution_text += "\n"
|
||||
self.solution_display.set_text(solution_text)
|
||||
|
||||
def on_paste_button_clicked(self):
|
||||
text = QApplication.clipboard().text()
|
||||
try:
|
||||
input_np = np.fromstring(text, dtype=np.float64, sep=" ")
|
||||
|
||||
n = 0.5 * (np.sqrt(4.0 * input_np.shape[0] + 1.0) - 1.0)
|
||||
if n % 1.0 != 0.0:
|
||||
return
|
||||
n = int(n)
|
||||
|
||||
input_np = np.reshape(input_np, (n, n + 1))
|
||||
|
||||
self.n_input.set_value(str(n))
|
||||
|
||||
self.matrix_a = np.copy(input_np[:n, :n])
|
||||
self.matrix_b = np.copy(input_np[:n, n:])
|
||||
|
||||
self.set_matrix(self.matrix_a, self.matrix_b)
|
||||
|
||||
except Exception as e:
|
||||
print(e)
|
||||
return
|
||||
|
||||
def on_n_input_changed(self, widget: InputField):
|
||||
MAX_N = 8
|
||||
|
||||
on_input_int_number(widget)
|
||||
try:
|
||||
n = int(widget.get_value())
|
||||
if n < 1:
|
||||
widget.set_value(str(1))
|
||||
return
|
||||
if n > MAX_N:
|
||||
widget.set_value(str(MAX_N))
|
||||
return
|
||||
|
||||
self.matrix.recreate(int(self.n_input.get_value()))
|
||||
self.input_matrix_from_widget()
|
||||
self.update_stats()
|
||||
except:
|
||||
return
|
||||
|
||||
def on_reset_button_clicked(self):
|
||||
self.n_input.set_value(str(4))
|
||||
self.set_matrix(task.A(), task.B())
|
||||
|
||||
def on_matrix_changed(self, widget: InputField):
|
||||
on_input_float_number(widget)
|
||||
|
||||
try:
|
||||
self.input_matrix_from_widget()
|
||||
self.update_stats()
|
||||
except:
|
||||
return
|
||||
|
||||
def input_matrix_from_widget(self):
|
||||
try:
|
||||
self.matrix_a = np.matrix(
|
||||
[
|
||||
[
|
||||
self.matrix.get_value_x(i, j)
|
||||
for j in range(self.matrix.rows[0].x_inputs.__len__())
|
||||
]
|
||||
for i in range(self.matrix.rows.__len__())
|
||||
],
|
||||
dtype=np.float64,
|
||||
)
|
||||
self.matrix_b = np.matrix(
|
||||
[
|
||||
[self.matrix.get_value_b(i)]
|
||||
for i in range(self.matrix.rows.__len__())
|
||||
],
|
||||
dtype=np.float64,
|
||||
)
|
||||
except:
|
||||
return
|
||||
|
||||
def update_stats(self):
|
||||
if not self.initialized:
|
||||
return
|
||||
|
||||
self.solution_display.set_visible(False)
|
||||
|
||||
try:
|
||||
self.det_display.set_text(f"{algorithm.det(self.matrix_a):.5f}")
|
||||
self.cond_display.set_text(f"{algorithm.cond(self.matrix_a):.5f}")
|
||||
except:
|
||||
self.det_display.set_text("Невозможно вычислить")
|
||||
self.cond_display.set_text("Невозможно вычислить")
|
||||
|
||||
def set_matrix(self, A: np.matrix, B: np.matrix):
|
||||
for i in range(A.shape[0]):
|
||||
for j in range(A.shape[1]):
|
||||
self.matrix.set_value_x(i, j, str(A[i, j]))
|
||||
|
||||
for i in range(B.shape[0]):
|
||||
self.matrix.set_value_b(i, str(B[i, 0]))
|
||||
|
||||
self.update_stats()
|
||||
Reference in New Issue
Block a user