Форум программистов, компьютерный форум, киберфорум
iamvic
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
Путевые заметки в процессе познания Python и PyQt/PySide.
Помни - только тег CODE не портит код добавлением пробела в начало пустой строки.

По итогам определения начального экрана при старте приложения

Запись от iamvic размещена 21.04.2021 в 13:19
Показов 3211 Комментарии 0

Пока не забылось, изложу последовательно всю эпопею и подведу некоторые итоги.
Пусть будет тут в назидание мне и интересующимся. Уж больно забавный результат
получился .

Если по порядку, то всё началось с пожелания, чтобы главное окно приложения
открывалось именно на том экране многоэкранной системы, с которого его запустили.

Под многоэкранной системой здесь понимается компьютер, к видеосистеме которого
подключены несколько мониторов, один из которых — основной, а остальные —
дополнительные. В общем случае, эти мониторы могут иметь разные размеры
и разрешение экрана.

Старт приложения может выполняться как щелчком ЛКМ по значку запуска приложения,
расположенном на экране, так и из командной строки в окне терминала, открытого
на этом экране. Приложение должно определить экран, с которого его запустили,
открыть главное окно приложения размером в половину высоты и ширины этого экрана
и разместить его по центру данного экрана.

Ну и до кучи, приложение должно быть кроссплатформенным и работать одинаково
как под Windows, так и под Linux.

И что тут сложного? Задачка-то тривиальная. Пишем пробник:
Python
1
2
3
4
5
6
7
8
9
10
11
12
#!/usr/bin/python3
# -*- coding: utf-8 -*-
import sys
from PyQt5.QtWidgets import QApplication
from PyQt5.QtWidgets import QMainWindow
 
if __name__ == '__main__':
    app = QApplication(sys.argv)
 
    mwin = QMainWindow()
    mwin.show()
    sys.exit(app.exec_())
Раскидываем значки по экранам, проверяем, убеждаемся, что по щелчкам ЛКМ на значках
приложение сразу открывает своё окно на нужном экране и под Linux, и под Windows.
Убеждаемся, что и для командной строки результат аналогичен. Чего тут думать-то?
Осталось-то только поменять размер окна под выбранный экран, отцентровать его и...
эпично лажануться .

Это только кажется, что решение уже найдено. На самом деле, полного решения
не существует в рамках ограничений, накладываемых постановкой задачи.

В качестве примера приведу некий код, на котором можно проверить все утверждения,
приводимые ниже (убрал под спойлер для истории).

Кликните здесь для просмотра всего текста
Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
#!/usr/bin/python3
# -*- coding: utf-8 -*-
"""QScreen Probe v0.003
 
Пример реализации оконного приложения с изменением геометрии окна
в многоэкранных системах, когда приложение должно открывать
рабочее окно именно на том экране, с которого его запустили.
"""
 
import sys, os, platform, time
from PyQt5 import Qt
from PyQt5.QtWidgets import QApplication
from PyQt5.QtCore import PYQT_VERSION_STR, QT_VERSION_STR
from PyQt5.QtCore import pyqtSignal, pyqtSlot
from PyQt5.QtCore import QTimer
from PyQt5.QtWidgets import QAction, QApplication
from PyQt5.QtWidgets import QLabel, QMainWindow, QMessageBox
 
APP_NAME = 'QScreen Probe v0.003'
 
def probe_get_screen(client):
    """Определяем экран, выбранный системой для отрисовки окна:
 
    selected_screen = probe_get_screen(client)
    """
    selected_screen = None
    if (int(QT_VERSION_STR.split('.')[1]) >= 10 and
        int(PYQT_VERSION_STR.split('.')[1]) >= 10):
 
        selected_screen = QApplication.screenAt(client.geometry().bottomLeft())
    else:
        screens = QApplication.screens()
        if len(screens) > 0:
            for i in range(len(screens)):
                if screens[i].geometry().contains(client.geometry().bottomLeft()):
                    selected_screen = screens[i]
    return selected_screen
 
 
 
class ProbeMainWindow(QMainWindow):
    """Главное окно приложения
    """
    is_first_show = True
 
    def __init__(self, parent=None):
        super(ProbeMainWindow, self).__init__(parent)
        self.initUI()
 
    def initUI(self):
        self.setWindowTitle(APP_NAME)
        self.statusBar()
 
        orphanAction = QAction(
            'Без родителя', self, shortcut='Ctrl+1',
            statusTip='Окно сообщения, у которого нет родителя',
            triggered=self.to_orphan, enabled=True)
 
        infantAction = QAction(
            'С родителем', self, shortcut='Ctrl+2',
            statusTip='Окно сообщения, у которого есть родитель',
            triggered=self.to_infant, enabled=True)
 
        exitAction = QAction(
            'Выход', self, shortcut='Ctrl+Q',
            statusTip='Завершить работу приложения',
            triggered=self.to_close, enabled=True)
 
        taskMenu = self.menuBar().addMenu('Файл')
        taskMenu.addAction(orphanAction)
        taskMenu.addAction(infantAction)
        taskMenu.addAction(exitAction)
 
        infoText = QLabel('Главное окно приложения открывается:\n\n'
            'под Windows - на том экране, на котором в момент открытия\n'
            'окна располагается указатель мыши,\n\n'
            'под Linux - на том экране, с которого запустили приложение.')
        self.setCentralWidget(infoText)
 
        # Поскольку графический интерфейс надо построить с учётом того,
        # что приложение может быть запущено в многоэкранных системах,
        # то предварительно требуется узнать какой экран использует
        # система для размещения окна приложения.
        # Поэтому просто ждём сработки self.showEvent()
        # после выполнения mwin.show() в __main__.
 
    def showEvent(self, event):
        if self.isVisible() and self.is_first_show:
            # Ловим первое событие отрисовки окна и отправляем окно
            # на изменение геометрии.
            # Поскольку в Linux требуется некоторое время, чтобы X11
            # успел отрисовать окно, а Windows готова сразу,
            # то, чтобы не множить сущности, просто отправляем сигнал
            # на изменение геометрии с соответствущей задержкой.
 
            self.is_first_show = False
            custom_delay = 150
            if sys.platform == 'win32':
                custom_delay = 0
            QTimer.singleShot(custom_delay, self.to_custom)
 
        super(ProbeMainWindow, self).showEvent(event)
 
    @pyqtSlot()
    def to_custom(self):
        """Меняем геометрию окна
        """
        selected_screen = probe_get_screen(self)
 
        if selected_screen is None:
            # нет устройств отображения
            print('ОШИБКА! Текущий экран не определён.')
            self.to_close()
        else:
            current_geo = selected_screen.availableGeometry()
            self.setGeometry(
                current_geo.x() + current_geo.width() // 4,
                current_geo.y() + current_geo.height() // 4,
                current_geo.width() // 2,
                current_geo.height() // 2)
 
    def to_orphan(self):
        # моделируем затяжное формирование окна
        # time.sleep(3)
 
        x = QMessageBox.warning(
                None, 'БЕЗ РОДИТЕЛЯ',
                'Окно этого сообщения открывается на том экране,'
                ' где в данный момент располагается указатель мыши.')
 
    def to_infant(self):
        # моделируем затяжное формирование окна
        # time.sleep(3)
 
        x = QMessageBox.information(
                self, 'С РОДИТЕЛЕМ',
                'Окно этого сообщения открывается на том же экране,'
                ' где находится родитель (главное окно).')
 
    def to_close(self):
        """Завершаем работу.
        """
        self.close()
 
 
if __name__ == '__main__':
    app = QApplication(sys.argv)
 
    # моделируем затяжной пуск приложения
    # time.sleep(3)
 
    # если есть хоть один параметр, то пуск - аварийный
    if len(sys.argv) > 1:
        x = QMessageBox.critical(
                None, 'АВАРИЯ',
                'Окно этого сообщения открывается на том экране,'
                ' где в данный момент располагается указатель мыши.\n\n'
                'Работа приложения {!s} будет завершена.'.format(APP_NAME))
        sys.exit(1)
 
    # нормальный запуск приложения
    mwin = ProbeMainWindow()
    mwin.show()
    sys.exit(app.exec_())


Сначала о хорошем — Linux может. Но только за счёт особенностей X11, частично
разбираемых в последнем разделе тут https://doc.qt.io/qt-5/application-windows.html
и, видимо, нарушающих в какой-то степени принятые соглашения о пользовательском
интерфейсе для окон верхнего уровня.

Здесь сигнал на изменение геометрии окна приходится посылать из обработчика
события showEvent с некоторой задержкой, но экран, с которого запустили приложение,
в результате определяется правильно. По крайней мере, на Lubutu, Xubuntu и OpenSUSE
работает, а покрыть всю линейку одному — здоровья не хватит . Недостатки видны
сразу — мелькание артефактного окна. Но это следствие того, что окно должно быть
уже прорисовано до изменения геометрии.

Windows задержки не требует, но в качестве экрана для запуска приложения всегда
выбирает тот, на котором в момент открытия окна находится указатель мыши (sic!).
Надо сказать, что поначалу это обескураживает даже матёрых пользователей Windows,
которые раньше просто не работали с многоэкранными системами. Например, ситуация,
когда приложение запускается достаточно долго, а пользователь, стартовавший
приложение, успевает переместить указатель мыши на другой экран до открытия окна
приложения, поначалу не вызывает понимания.

Ничего необычного в таком выборе экрана нет. Похоже, такое поведение полностью
соответствует принятым соглашениям о пользовательском интерфейсе для окон верхнего
уровня. Например, даже в Linux окна верхнего уровня, создаваемые функциями типа:
Python
1
result = QMessageBox.critical(None, 'Авария !!!')
открываются именно на том экране, на котором находится указатель мыши. Видимо,
в этом случае приняты необходимые и достаточные меры, чтобы соответствовать
стандарту.

Если постановку задачи не изменить, то выходом из ситуации видится только
дрессировка пользователей Windows, которых следует приучить удерживать
указатель мыши до открытия окна приложения на том экране, с которого
оно запущено.

Это дело неблагодарное. Дешевле изменить постановку и сделать явное указание экрана
через параметры запуска или придумать что-нибудь с конфигурированием.

Дополнение от 17.02.2022:

Однако, надо забить последний гвоздь в эту тему и больше уже к ней не возвращаться.

Для начала надо внести поправочку в формулировки, потому как под Linux начальное (главное)
окно открывается всё-таки не на том экране, с которого запустили приложение, а на экране,
который был активным во время открытия окна:
Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
#!/usr/bin/python3
# -*- coding: utf-8 -*-
"""QScreen Probe v0.004
 
Пример реализации оконного приложения с изменением геометрии окна
в многоэкранных системах, когда приложение должно открывать
главное окно на активном экране.
"""
 
import sys
from PyQt5.QtCore import Qt
from PyQt5.QtCore import PYQT_VERSION_STR, QT_VERSION_STR
from PyQt5.QtCore import pyqtSignal, pyqtSlot
from PyQt5.QtCore import QTimer
from PyQt5.QtGui import QFont
from PyQt5.QtWidgets import QApplication
from PyQt5.QtWidgets import QAction, QHBoxLayout, QWidget
from PyQt5.QtWidgets import QLabel, QMainWindow, QMessageBox
 
APP_NAME = 'QScreen Probe v0.004'
 
def probe_get_screen(client):
    """Определяем экран, выбранный системой для отрисовки окна:
 
    selected_screen = probe_get_screen(client)
    """
 
    selected_screen = QApplication.screens()[0]
    if (int(QT_VERSION_STR.split('.')[1]) >= 10 and
        int(PYQT_VERSION_STR.split('.')[1]) >= 10):
 
        selected_screen = QApplication.screenAt(client.geometry().bottomLeft())
    else:
        screens = QApplication.screens()
        if len(screens) > 0:
            for i in range(len(screens)):
                if screens[i].geometry().contains(client.geometry().bottomLeft()):
                    selected_screen = screens[i]
    return selected_screen
 
 
 
class ProbeMainWindow(QMainWindow):
    """Главное окно приложения
    """
    def __init__(self, parent=None):
        super(ProbeMainWindow, self).__init__(parent)
        self.is_first_show = True
        # Поскольку графический интерфейс надо построить с учётом того,
        # что приложение может быть запущено в многоэкранных системах,
        # то предварительно требуется узнать какой экран использует
        # система для размещения окна приложения.
        # Поэтому просто ждём сработки self.showEvent()
        # после выполнения mwin.show() в __main__.
 
    def showEvent(self, event):
        if self.isVisible() and self.is_first_show:
            # X11 в Linux запаздывает с отрисовкой первого окна
            # верхнего уровня, поэтому ловим первое событие
            # отрисовки и отправляем окно на изменение размеров
            # и расположения с соответствующей задержкой.
 
            self.is_first_show = False
            QTimer.singleShot(80 if sys.platform == 'linux' else 10,
                              self.to_custom)
 
        super(ProbeMainWindow, self).showEvent(event)
 
    @pyqtSlot()
    def to_custom(self):
        """Центруем, меняем размеры окна под выбранный системой экран
        и отрисовываем графический интерфейс
        """
        selected_screen = probe_get_screen(self)
 
        current_geo = selected_screen.availableGeometry()
        self.move(current_geo.x() + current_geo.width() // 4,
                  current_geo.y() + current_geo.height() // 4)
        self.resize(current_geo.width() // 2,
                    current_geo.height() // 2)
 
        QApplication.processEvents()
 
        self.setWindowTitle(APP_NAME)
        self.statusBar()
 
        QApplication.processEvents()
 
        orphanAction = QAction(
            'Без родителя', self, shortcut='Ctrl+1',
            statusTip='Окно сообщения, у которого нет родителя',
            triggered=self.to_orphan, enabled=True)
 
        infantAction = QAction(
            'С родителем', self, shortcut='Ctrl+2',
            statusTip='Окно сообщения, у которого есть родитель',
            triggered=self.to_infant, enabled=True)
 
        exitAction = QAction(
            'Выход', self, shortcut='Ctrl+Q',
            statusTip='Завершить работу приложения',
            triggered=self.to_close, enabled=True)
 
        taskMenu = self.menuBar().addMenu('Файл')
        taskMenu.addAction(orphanAction)
        taskMenu.addAction(infantAction)
        taskMenu.addAction(exitAction)
 
        infoText = QLabel(
            'При запуске на многоэкранных системах главное окно\n'
            'этого приложения открывается:\n\n'
            'под Windows - на том экране, на котором в момент открытия\n'
            'окна находится указатель мыши,\n\n'
            'под Linux - на том экране, который был активен в момент\n'
            'открытия окна.\n\n\n\n'
            'Ctrl-1 - сообщение без родителя откроется на том экране,\n'
            'где находится указатель мыши.\n\n'
            'Ctrl-2 - сообщение с родителем откроется на том экране,\n'
            'где находится родитель (главное окно).'
            )
        font = infoText.font()
        font.setWeight(QFont.Bold)
        infoText.setFont(font)
 
        main_map = QHBoxLayout(None)
        main_map.addStretch(1)
        main_map.addWidget(infoText)
        main_map.addStretch(1)
 
        central_widget = QWidget(self)
        central_widget.setLayout(main_map)
        self.setCentralWidget(central_widget)
 
    def to_orphan(self):
        QMessageBox.warning(
            None, 'БЕЗ РОДИТЕЛЯ',
            'Окно этого сообщения открывается на том экране,'
            ' где в данный момент располагается указатель мыши.')
 
    def to_infant(self):
        QMessageBox.information(
            self, 'С РОДИТЕЛЕМ',
            'Окно этого сообщения открывается на том же экране,'
            ' где находится родитель (главное окно).')
 
    def to_close(self):
        """Завершаем работу.
        """
        self.close()
 
 
if __name__ == '__main__':
    app = QApplication(sys.argv)
 
    # если есть хоть один параметр, то пуск - аварийный
    if len(sys.argv) > 1:
        QMessageBox.critical(
            None, 'АВАРИЯ',
            'Окно этого сообщения открывается на том экране,'
            ' где в данный момент располагается указатель мыши.\n\n'
            'Работа приложения {!s} будет завершена.'.format(APP_NAME))
        sys.exit(1)
 
    # нормальный запуск приложения
    mwin = ProbeMainWindow()
 
    import time
    time.sleep(3)
 
    mwin.show()
    sys.exit(app.exec_())
Выглядит это так. Например, запускаем приложение с задержкой исполнения из сессии командной
строки, открытой на дополнительном экране:
Code
1
sleep 3 && python3 screenprobe.py
Если затем просто переместить указатель мыши на основной экран, то приложение откроется
на дополнительном экране. А если при этом щёлкнуть ЛКМ, активировав основной экран,
то приложение откроется уже на основном. Под Windows же, и в том, и в другом случае,
приложение открывается на основном экране (щёлкать ЛКМ не надо, главное - указатель мыши перевести).

А поскольку именно такого поведения требуют принятые соглашения о пользовательском
интерфейсе для окон верхнего уровня (которые Linux нарушает, как это было сказано выше),
то проще, как оказалось, добавить соответствующий код в приложение, чтобы его поведение
было одинаковым и тут, и там:
Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
#!/usr/bin/python3
# -*- coding: utf-8 -*-
"""QScreen Probe v0.005
 
Пример реализации оконного приложения с изменением геометрии окна
в многоэкранных системах, когда приложение должно открывать
рабочее окно на том экране, на котором в момент открытия находится
указатель мыши.
"""
 
import sys
from PyQt5.QtCore import PYQT_VERSION_STR, QT_VERSION_STR
from PyQt5.QtCore import pyqtSignal, pyqtSlot
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QCursor, QFont
from PyQt5.QtWidgets import QApplication
from PyQt5.QtWidgets import QAction, QHBoxLayout, QWidget
from PyQt5.QtWidgets import QLabel, QMainWindow, QMessageBox
 
APP_NAME = 'QScreen Probe v0.005'
 
def probe_cursor_screen(client):
    """Определяем экран, на котором находится указатель мыши:
 
    selected_screen = probe_cursor_screen(client)
    """
 
    selected_screen = QApplication.screens()[0]
    if (int(QT_VERSION_STR.split('.')[1]) >= 10 and
        int(PYQT_VERSION_STR.split('.')[1]) >= 10):
 
        selected_screen = QApplication.screenAt(QCursor.pos())
    else:
        screens = QApplication.screens()
        if len(screens) > 0:
            for i in range(len(screens)):
                if screens[i].geometry().contains(QCursor.pos()):
                    selected_screen = screens[i]
    return selected_screen
 
 
 
class ProbeMainWindow(QMainWindow):
    """Главное окно приложения
    """
    def __init__(self, parent=None):
        super(ProbeMainWindow, self).__init__(parent)
        self.is_first_show = True
        self.initUI()
 
    def initUI(self):
        self.setWindowTitle(APP_NAME)
        self.statusBar()
 
        orphanAction = QAction(
            'Без родителя', self, shortcut='Ctrl+1',
            statusTip='Окно сообщения, у которого нет родителя',
            triggered=self.to_orphan, enabled=True)
 
        infantAction = QAction(
            'С родителем', self, shortcut='Ctrl+2',
            statusTip='Окно сообщения, у которого есть родитель',
            triggered=self.to_infant, enabled=True)
 
        exitAction = QAction(
            'Выход', self, shortcut='Ctrl+Q',
            statusTip='Завершить работу приложения',
            triggered=self.to_close, enabled=True)
 
        taskMenu = self.menuBar().addMenu('Файл')
        taskMenu.addAction(orphanAction)
        taskMenu.addAction(infantAction)
        taskMenu.addAction(exitAction)
 
        infoText = QLabel(
            'При запуске на многоэкранных системах главное окно\n'
            'этого приложения и под Windows, и под Linux открывается\n'
            'на том экране, на котором в момент открытия окна\n'
            'находится указатель мыши.\n\n\n\n'
            'Ctrl-1 - сообщение без родителя откроется на том экране,\n'
            'где находится указатель мыши.\n\n'
            'Ctrl-2 - сообщение с родителем откроется на том экране,\n'
            'где находится родитель (главное окно).'
            )
        font = infoText.font()
        font.setWeight(QFont.Bold)
        infoText.setFont(font)
 
        main_map = QHBoxLayout(None)
        main_map.addStretch(1)
        main_map.addWidget(infoText)
        main_map.addStretch(1)
 
        central_widget = QWidget(self)
        central_widget.setLayout(main_map)
        self.setCentralWidget(central_widget)
 
        # Центруем и меняем размеры окна под экран, на котором находится
        # указатель мыши (актуально для Linux и Windows не портит)
        selected_screen = probe_cursor_screen(self)
 
        current_geo = selected_screen.availableGeometry()
        self.move(current_geo.x() + current_geo.width() // 4,
                  current_geo.y() + current_geo.height() // 4)
        self.resize(current_geo.width() // 2,
                    current_geo.height() // 2)
 
    def to_orphan(self):
        QMessageBox.warning(
            None, 'БЕЗ РОДИТЕЛЯ',
            'Окно этого сообщения открывается на том экране,'
            ' где в данный момент располагается указатель мыши.')
 
    def to_infant(self):
        QMessageBox.information(
            self, 'С РОДИТЕЛЕМ',
            'Окно этого сообщения открывается на том же экране,'
            ' где находится родитель (главное окно).')
 
    def to_close(self):
        """Завершаем работу.
        """
        self.close()
 
 
if __name__ == '__main__':
    app = QApplication(sys.argv)
 
    # если есть хоть один параметр, то пуск - аварийный
    if len(sys.argv) > 1:
        QMessageBox.critical(
            None, 'АВАРИЯ',
            'Окно этого сообщения открывается на том экране,'
            ' где в данный момент располагается указатель мыши.\n\n'
            'Работа приложения {!s} будет завершена.'.format(APP_NAME))
        sys.exit(1)
 
    # нормальный запуск приложения
    mwin = ProbeMainWindow()
    mwin.show()
    sys.exit(app.exec_())
История вопроса здесь:
Как определить во время инициализации на какой экран отрисуется окно?
https://www.cyberforum.ru/blog... g6887.html
https://www.cyberforum.ru/blog... g6917.html
Размещено в Памятка
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Всего комментариев 0
Комментарии
 
Новые блоги и статьи
Музыка, написанная Искусственным Интеллектом
volvo 04.12.2025
Всем привет. Некоторое время назад меня заинтересовало, что уже умеет ИИ в плане написания музыки для песен, и, собственно, исполнения этих самых песен. Стихов у нас много, уже вышли 4 книги, еще 3. . .
От async/await к виртуальным потокам в Python
IndentationError 23.11.2025
Армин Ронахер поставил под сомнение async/ await. Создатель Flask заявляет: цветные функции - провал, виртуальные потоки - решение. Не threading-динозавры, а новое поколение лёгких потоков. Откат?. . .
Поиск "дружественных имён" СОМ портов
Argus19 22.11.2025
Поиск "дружественных имён" СОМ портов На странице: https:/ / norseev. ru/ 2018/ 01/ 04/ comportlist_windows/ нашёл схожую тему. Там приведён код на С++, который показывает только имена СОМ портов, типа,. . .
Сколько Государство потратило денег на меня, обеспечивая инсулином.
Programma_Boinc 20.11.2025
Сколько Государство потратило денег на меня, обеспечивая инсулином. Вот решила сделать интересный приблизительный подсчет, сколько государство потратило на меня денег на покупку инсулинов. . . .
Ломающие изменения в C#.NStar Alpha
Etyuhibosecyu 20.11.2025
Уже можно не только тестировать, но и пользоваться C#. NStar - писать оконные приложения, содержащие надписи, кнопки, текстовые поля и даже изображения, например, моя игра "Три в ряд" написана на этом. . .
Мысли в слух
kumehtar 18.11.2025
Кстати, совсем недавно имел разговор на тему медитаций с людьми. И обнаружил, что они вообще не понимают что такое медитация и зачем она нужна. Самые базовые вещи. Для них это - когда просто люди. . .
Создание Single Page Application на фреймах
krapotkin 16.11.2025
Статья исключительно для начинающих. Подходы оригинальностью не блещут. В век Веб все очень привыкли к дизайну Single-Page-Application . Быстренько разберем подход "на фреймах". Мы делаем одну. . .
Фото: Daniel Greenwood
kumehtar 13.11.2025
Расскажи мне о Мире, бродяга
kumehtar 12.11.2025
— Расскажи мне о Мире, бродяга, Ты же видел моря и метели. Как сменялись короны и стяги, Как эпохи стрелою летели. - Этот мир — это крылья и горы, Снег и пламя, любовь и тревоги, И бескрайние. . .
PowerShell Snippets
iNNOKENTIY21 11.11.2025
Модуль PowerShell 5. 1+ : Snippets. psm1 У меня модуль расположен в пользовательской папке модулей, по умолчанию: \Documents\WindowsPowerShell\Modules\Snippets\ А в самом низу файла-профиля. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2025, CyberForum.ru