сейчас имена скважин для обучающей и валидационной выборок отображаются в окнах. я хочу сделать так, чтобы в этих окнах их можно было выбирать (например, галочками) для дальнейшей работы. как мне это сделать?
вот мой код:
import math
import os
from PySide6.QtWidgets import QApplication, QWidget, QVBoxLayout, \
    QLabel, QPushButton, QFormLayout, QLineEdit, QComboBox, QListWidget, \
        QMessageBox, QSpinBox, QDoubleSpinBox, QFileDialog, QScrollArea

import sys
if os.path.realpath('.') not in sys.path:
    sys.path.append(os.path.realpath('.'))

from qt_app.utils import get_wells_names

WAVELET_TRAINING_OPTIONS = {
    'импульс Рикера с фиксированными параметрами': 'ricker_fix',
    'импульс Рикера с обучением параметров': 'ricker_train',
    'обучение произвольного импульса': 'random_train'
}

class TrainApp(QWidget):
    def __init__(self):
        super().__init__()
        self.setWindowTitle('Обучение модели предсказания импеданса')
        layout = QVBoxLayout()

        # Create scroll area
        scroll_area = QScrollArea()
        scroll_area.setWidgetResizable(True)
        
        # Create a widget to hold the form content
        scroll_widget = QWidget()
        scroll_layout = QVBoxLayout(scroll_widget)

        form_layout = QFormLayout()
        self.x_data_path_line_edit = QLineEdit()
        self.y_data_path_line_edit = QLineEdit()
        self.wells_data_path_line_edit = QLineEdit()
        self.val_wellnames_list_widget = QListWidget()
        self.train_wellnames_list_widget = QListWidget()
        self.save_path_line_edit = QLineEdit()
        self.n_epochs_spin_box = QSpinBox(value=50)
        self.patch_size_spin_box = QSpinBox(value=128)
        self.batch_size_spin_box = QSpinBox(value=32)
        self.os_size_spin_box = QSpinBox(value=64)
        self.val_size_spin_box = QSpinBox(value=100)
        self.learning_rate_double_spin_box = QDoubleSpinBox(value=1e-4, decimals=6)
        self.global_loss_coef_double_spin_box = QDoubleSpinBox(value=0.05, decimals=6)
        self.train_wavelet_mode_combo_box = QComboBox()
        self.train_wavelet_mode_combo_box.addItems(WAVELET_TRAINING_OPTIONS.keys())
        self.wavelet_freq_double_spin_box = QDoubleSpinBox(value=10)
        self.wavelet_length_double_spin_box = QDoubleSpinBox(value=0.128, decimals=6)
        self.wavelet_dt_double_spin_box = QDoubleSpinBox(value=0.004, decimals=6)
        self.max_n_wells_on_plot_spin_box = QSpinBox(value=0)
        self.training_axes_combo_box = QComboBox()
        self.training_axes_combo_box.addItems(['0', '1'])
        self.clearml_project_name_line_edit = QLineEdit()

        form_layout.addRow('Имя файла датасете (x_data):', self.x_data_path_line_edit)
        select_x_data_file_button = QPushButton('Выбрать файл x_data')
        select_x_data_file_button.clicked.connect(lambda: self.select_file(self.x_data_path_line_edit, ext_filter="*.npy"))
        form_layout.addRow(select_x_data_file_button)
        form_layout.addRow(QLabel('Имя файла импеданса (y_data)'), self.y_data_path_line_edit)
        select_y_data_file_button = QPushButton('Выбрать файл y_data')
        select_y_data_file_button.clicked.connect(lambda: self.select_file(self.y_data_path_line_edit, ext_filter="*.npy"))
        form_layout.addRow(select_y_data_file_button)
        form_layout.addRow(QLabel('Имя файла скважин (wells_data)'), self.wells_data_path_line_edit)
        select_wells_data_file_button = QPushButton('Выбрать файл скважин (wells_data)')
        select_wells_data_file_button.clicked.connect(self.select_wells_data_and_load_names)
        form_layout.addRow(select_wells_data_file_button)
        form_layout.addRow('Валидационные скважины:', self.val_wellnames_list_widget)
        form_layout.addRow('Обучающие скважины:', self.train_wellnames_list_widget)
        form_layout.addRow(QLabel('Путь для сохранения весов модели'), self.save_path_line_edit)
        select_save_path_button = QPushButton('Выбрать путь для сохранения')
        select_save_path_button.clicked.connect(lambda: self.select_directory(self.save_path_line_edit))
        form_layout.addRow(select_save_path_button)
        form_layout.addRow('Количество эпох обучения', self.n_epochs_spin_box)
        form_layout.addRow('patch_size', self.patch_size_spin_box)
        form_layout.addRow('batch_size', self.batch_size_spin_box)
        form_layout.addRow('os_size', self.os_size_spin_box)
        form_layout.addRow('val_size', self.val_size_spin_box)
        form_layout.addRow(QLabel('learning_rate'), self.learning_rate_double_spin_box)
        form_layout.addRow('global_loss_coef', self.global_loss_coef_double_spin_box)
        form_layout.addRow(QLabel('Режим обучения импульса'), self.train_wavelet_mode_combo_box)
        form_layout.addRow('wavelet_freq', self.wavelet_freq_double_spin_box)
        form_layout.addRow('wavelet_length', self.wavelet_length_double_spin_box)
        form_layout.addRow('wavelet_dt', self.wavelet_dt_double_spin_box)
        form_layout.addRow(QLabel('Максимальное количество скважин на рисунке'), self.max_n_wells_on_plot_spin_box)
        form_layout.addRow(QLabel('Выбрать ось куба для обучения'), self.training_axes_combo_box)
        form_layout.addRow('Имя проекта для сохранения в ClearML', self.clearml_project_name_line_edit)

        # Add form layout to scroll widget
        scroll_layout.addLayout(form_layout)
        
        # Set the scroll widget as the widget for scroll area
        scroll_area.setWidget(scroll_widget)
        
        # Add scroll area to main layout
        layout.addWidget(scroll_area)
        # layout.addLayout(form_layout)
        run_button = QPushButton('Начать обучение')
        run_button.clicked.connect(self.start_training)
        layout.addWidget(run_button)



        self.setLayout(layout)


    def select_file(self, widget, ext_filter="*"):
        file_path, _ = QFileDialog.getOpenFileName(self, "Выбрать файл", "", ext_filter)
        if file_path:
            widget.setText(file_path)


    def select_directory(self, widget):
        directory_path = QFileDialog.getExistingDirectory(self, 'Выбрать директорию')
        if directory_path:
            widget.setText(directory_path)

    def select_wells_data_and_load_names(self):
        """
        Выбирает файл wells_data и загружает имена скважин в списки
        """
        file_path, _ = QFileDialog.getOpenFileName(self, "Выбрать файл скважин", "", "*.pickle")
        if file_path:
            # Установить путь к файлу
            self.wells_data_path_line_edit.setText(file_path)
            
            try:
                # Получить имена скважин
                well_names = get_wells_names(file_path)
                
                # Очистить существующие списки
                self.val_wellnames_list_widget.clear()
                self.train_wellnames_list_widget.clear()
                
                # Добавить имена скважин в списки
                self.val_wellnames_list_widget.addItems(well_names)
                self.train_wellnames_list_widget.addItems(well_names)
                
            except Exception as e:
                QMessageBox.warning(self, "Ошибка", f"Не удалось загрузить имена скважин: {str(e)}")
    

    def start_training(self):
        if not self.val_wellnames_list_widget.selectedItems():
            QMessageBox.warning(self, 'Ошибка', 'Не выбраны скважины для валидации')
            return
        elif not self.train_wellnames_list_widget.selectedItems() and not self.training_axes_combo_box.currentText().strip():
            QMessageBox.warning(self, 'Ошибка', 'Обучающая выборка пуста. Все скважины выбраны как валидационные')
            return

        train_wells = [item.text() for item in self.train_wellnames_list_widget.selectedItems()]
        val_wells = [item.text() for item in self.val_wellnames_list_widget.selectedItems()]

        save_path = os.path.abspath(self.save_path_line_edit.text())
        if not os.path.exists(save_path):
            os.makedirs(save_path)

        run_str = ['python', r'WELLS/SEIS_propagation/_2D/streamlit_app/_train_helper.py',
                     '--train_wavelet', self.train_wavelet_mode_combo_box.currentText(),
                     '--gen_lr', str(self.learning_rate_double_spin_box.value),
                     '--batch_size', str(self.batch_size_spin_box.value),
                     '--patch_size', str(self.patch_size_spin_box.value),
                     '--os_size', str(self.os_size_spin_box.value),
                     '--n_epochs', str(self.n_epochs_spin_box.value),
                     '--val_size', str(self.val_size_spin_box.value),
                     '--data_path', self.x_data_path_line_edit.text(),
                     '--labels_path', self.y_data_path_line_edit.text(),
                     '--well_labels_path', self.wells_data_path_line_edit.text(),
                     '--output_path', save_path,
                     '--train_wells', ','.join(train_wells),
                     '--val_wells', ','.join(val_wells),
                     '--global_loss_coef', str(self.global_loss_coef_double_spin_box.value),
                     '--max_n_wells_on_plot', str(self.max_n_wells_on_plot_spin_box.value),
                     '--training_axes', self.training_axes_combo_box.currentText(),
                           ]
        if self.clearml_project_name_line_edit.text():
            clearml_project_name = 'from_streamlit_app/' + self.clearml_project_name_line_edit.text()
            run_str.extend([
                '--clearml_project_name', str(clearml_project_name),
            ])
        if self.train_wavelet_mode_combo_box.currentText() == 'ricker_fix':
            run_str.extend([
                '--wavelet_freq', str(self.wavelet_freq_double_spin_box.value),
                '--wavelet_length', str(self.wavelet_length_double_spin_box.value),
                '--wavelet_dt', str(self.wavelet_dt_double_spin_box.value),
            ])
        elif self.train_wavelet_mode_combo_box.currentText() == 'ricker_train':
            run_str.extend([
                '--wavelet_frequency_limit', str(self.wavelet_freq_double_spin_box.value),
                '--wavelet_rotation_angle_limit', str(math.radians(self.training_axes_combo_box.currentText())),
                '--wavelet_amplitude_limit', str(self.training_axes_combo_box.currentText())
            ])

        process = subprocess.Popen(
            run_str,
            stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=True)
        while True:
            line = process.stdout.readline()
            if not line:
                break
            line = line.decode('UTF-8')
            print(line)
            if 'log_page' in line:
                st.info("Отслеживать обучение:\n" + line.split()[1])
        process.wait()

if __name__ == '__main__':
    app = QApplication(sys.argv)
    train_app = TrainApp()
    train_app.show()
    sys.exit(app.exec_())