Форум программистов, компьютерный форум, киберфорум
Python: GUI, графика
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.99/89: Рейтинг темы: голосов - 89, средняя оценка - 4.99
Эксперт Python
 Аватар для АмигоСП
295 / 108 / 57
Регистрация: 07.12.2016
Сообщений: 209

Обновление главного окна в PyQt5

07.12.2016, 15:50. Показов 19433. Ответов 38
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Доброго Всем времени суток. Наверное уже не раз создавались подобные темы, но ответа на свой вопрос так и не нашел( Поэтому спрошу еще раз, уж извиняйте. Вообщем имеется прога на питоне(3.5.2) По сути брут-перебиралка. На указанном сайте проверяет логины(зарегистрирован такой или нет). Делает она это через прокси, естественно. В консольной версии отрабатывает на ура и без проблем. В оконной же версии(через PyQt 5.6) прога отрабатывает свой цикл, но при этом главное окно “зависает”. Что мы делаем в главном окне: Выбираем файл с прокси(он добавляется в очередь Queue). Выбираем файл с логинами(он тоже добавляется в очередь Queue, но уже в другую). Выставляем кол-во потоков(модуль threading), задаём таймаут соединения(модуль grab), выбираем тип прокси(http/socks), указываем куда сохранить результат. Далее запускаем обработку в несколько потоков через threading. Во время обработки, если прокси сервер не срабатывает(через try - except), то логин снова добавляется в очередь. Если прокси в очереди закончились, то файл открывается заного и создаётся снова очередь с прокси. И так, пока не закончатся все логины. 'Хорошие логины' добавляются в список и потом отдельной функцией записываются в файл(результат, который указали при выборе сохранения). В инете встречаются примеры через QThread, либо QObject. Но все они для PyQt4. Хотелось бы понять вообще принцип - какие именно данные засовывать в QThread, либо QObject. Надо ли использовать питоновский модуль threading или все реализовывать через QTread. Вообщем смысл - чтобы главное окно не зависало(оно отображает еще промежуточную информацию через лейблы - сколько чего проверилось)
0
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
07.12.2016, 15:50
Ответы с готовыми решениями:

Дублирование главного окна при открытии нового окна
У меня есть основное окно типа QWidget, при нажатии на кнопку открывается окно типа QDialog. Но вместе с диалоговым окном открывается и...

PyQt5 При запуске окна из другого окна, методы класса не работают
Не знаю, как грамотно объяснить свою проблему, но предполагаю, что она точно в открытии нового окна по нажатию кнопки в другом окне. ...

Как мне сослаться на вторичные окна (формы) из главного окна
Мне скинули код.....я пытаюсь коды этих отдельных форм просмотреть в конструкторе.......то есть создав новый проект.......но наткнувшись на...

38
Эксперт С++
 Аватар для Avazart
8488 / 6155 / 615
Регистрация: 10.12.2010
Сообщений: 28,683
Записей в блоге: 30
08.12.2016, 21:52
Студворк — интернет-сервис помощи студентам
Можешь делать несколько раз запросы:
Python
1
2
3
4
5
6
url = QUrl(page_data["url"])
request = QNetworkRequest(url)
reply = self.manager.get(request) # QNetworkAccessManager. get()
reply.finished.connect(self.on_reply_finished)
reply.downloadProgress.connect(self.on_download_progress)
reply.setProperty("page_id", page_id)
А потом в слоте обрабатываешь результаты запросов

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
 def on_reply_finished(self):
        reply = self.sender()
        if reply.error() == QNetworkReply.NoError:
            content = reply.readAll()
            page_id = reply.property("page_id")
         # ....
        else:
            response_code = reply.attribute(QNetworkRequest.HttpStatusCodeAttribute)
            if (response_code is not None) and response_code != 200:
                self.error_msg("#"+str(response_code)+" "+reply.errorString())
            else:
                self.error_msg(reply.errorString()
        reply.deleteLater()
Без всяких подвисаний GUI.

В большинстве случаев подобная асинхронка это неудобно, но для большинства случаев есть requests.
Конкретно в данном случае может подойти.
0
2742 / 2341 / 620
Регистрация: 19.03.2012
Сообщений: 8,830
08.12.2016, 22:18
Цитата Сообщение от Avazart Посмотреть сообщение
В большинстве случаев подобная асинхронка это неудобно
Асинхронка это сложно, но профит радует. У меня есть проектик где надо оббегать и парсить данные 50 сайтов, там вот очень асинхронка выручает. Парсинг и скачивание выполняется ~ за 3 секунды.
0
Эксперт Python
 Аватар для АмигоСП
295 / 108 / 57
Регистрация: 07.12.2016
Сообщений: 209
08.12.2016, 22:20  [ТС]
Ух, сколько всего почитать)) я, как новичек, пока еще по простому пути. Разберусь в нём, а уж потом усложнять потихоньку)) А, кстати, по поводу модуля requests. Использовал его вначале, но потом, как оказалось он не обрабатывает SOCK5. Тупо игнорит его и запускает напрямую, не кидая никаких ошибок. Тестировал на нескольких ресурсах и везде показывал мой чистый IP. Спасибо вам большое за ответы. Буду разбираться
0
Эксперт С++
 Аватар для Avazart
8488 / 6155 / 615
Регистрация: 10.12.2010
Сообщений: 28,683
Записей в блоге: 30
08.12.2016, 22:44
Цитата Сообщение от alex925 Посмотреть сообщение
Асинхронка это сложно, но профит радует. У меня есть проектик где надо оббегать и парсить данные 50 сайтов, там вот очень асинхронка выручает. Парсинг и скачивание выполняется ~ за 3 секунды.
Асинхронка превращает код в запутанное УГ если нужно делать последовательные запросы, т.е авторизация+ ввод данных подтверждение итд...
В таких случаях лучше потоки имею ввиду реальные потоки, а не "псевдо" как python

Цитата Сообщение от АмигоСП Посмотреть сообщение
но потом, как оказалось он не обрабатывает SOCK5.
Хм, я не обратил внимание, возможно вы неправильно задали прокси?
0
2742 / 2341 / 620
Регистрация: 19.03.2012
Сообщений: 8,830
08.12.2016, 22:52
Цитата Сообщение от Avazart Посмотреть сообщение
В таких случаях лучше потоки имею ввиду реальные потоки, а не "псевдо" как python
Сугубо технически, они не "псевдо" потоки. Это реальные posix потоки, просто из-за гил происходит то, что код превращается из асинхронного в конкурентный.

Цитата Сообщение от Avazart Посмотреть сообщение
Асинхронка превращает код в запутанное УГ если нужно делать последовательные запросы
С aysncio не все так печально и код выглядит как синхронный, но работает асинхронно, так что все не так плохо)
0
Эксперт С++
 Аватар для Avazart
8488 / 6155 / 615
Регистрация: 10.12.2010
Сообщений: 28,683
Записей в блоге: 30
08.12.2016, 23:00
Цитата Сообщение от alex925 Посмотреть сообщение
Сугубо технически, они не "псевдо" потоки. Это реальные posix потоки, просто из-за гил происходит то, что код превращается из асинхронного в конкурентный.
Да что еще хуже, ибо потоки как бы есть, память жрут, но не выполняют своих ф-ций из-за блокировок.

Цитата Сообщение от alex925 Посмотреть сообщение
С aysncio не все так печально и код выглядит как синхронный, но работает асинхронно, так что все не так плохо)
Каким образом он может выглядеть как синхронный?
0
2742 / 2341 / 620
Регистрация: 19.03.2012
Сообщений: 8,830
08.12.2016, 23:05
Цитата Сообщение от Avazart Посмотреть сообщение
Каким образом он может выглядеть как синхронный?
Посмотри примеры кода на aiohttp

Цитата Сообщение от Avazart Посмотреть сообщение
что еще хуже, ибо потоки как бы есть, память жрут, но не выполняют своих ф-ций из-за блокировок.
Ну, что-же поделать, у всего есть + и - это нормально.
0
Эксперт С++
 Аватар для Avazart
8488 / 6155 / 615
Регистрация: 10.12.2010
Сообщений: 28,683
Записей в блоге: 30
08.12.2016, 23:41
Цитата Сообщение от АмигоСП Посмотреть сообщение
как оказалось он не обрабатывает SOCK5. Тупо игнорит его и запускает напрямую, не кидая никаких ошибок. Тестировал на нескольких ресурсах и везде показывал мой чистый IP.
Да действительно requests не подхватывает прокси SOCKS5 по чему-то

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import re
import requests
 
 
def main():
    url = 'https://2ip.ru/'
    proxy_str = 'socks5://37.191.159.133:45554'
    proxy = {'http': proxy_str, 'https': proxy_str}
    r = requests.get(url, proxy)
    r.raise_for_status()
 
    p = r'((\d{1,3}\.){3}\d{1,3})'
    m = re.search(p, r.text)
    if m:
        print("ip:",m.group(0))
    else:
        print("ip not found.")
 
 
if __name__ == "__main__":
    main()
Добавлено через 15 минут
Цитата Сообщение от alex925 Посмотреть сообщение
Посмотри примеры кода на aiohttp
Хз, ничего не понял там вроде для веба.
Слабо себе представляю что бы он нормально выглядело.
0
2742 / 2341 / 620
Регистрация: 19.03.2012
Сообщений: 8,830
09.12.2016, 10:48
Цитата Сообщение от Avazart Посмотреть сообщение
Слабо себе представляю что бы он нормально выглядело.
А у меня в 1 из проектов используется, я представляю.

Avazart, вот пример у меня на компе завалялся, только тут в старом стиле оформлено, сейчас нужно использовать async и await.
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
import asyncio
import aiohttp
import lxml.html
 
 
@asyncio.coroutine
def get(*args, **kwargs):
    response = yield from aiohttp.request('GET', *args, **kwargs)
    return (yield from response.text())
 
 
def parsing_html(page):
    parser = lxml.html.fromstring(page)
    res = parser.cssselect('span#dle-speedbar')
    return res[0].text_content()
 
 
@asyncio.coroutine
def downlaod_html(url):
    with (yield from sem):
        page = yield from get(url)
    html = parsing_html(page)
    print(html)
 
 
urls = [
    'http://filin.tv/fantastika/3825-flesh-the-flash-2-sezon.html',
    "http://filin.tv/fantastika/3973-koloniya-colony-1-sezon.html",
    "http://filin.tv/fantastika/3919-prostranstvo-the-expanse.html",
    "http://filin.tv/fantastika/1176-grimm-grimm-1-sezon-onlajn.html",
    "http://filin.tv/fantastika/3825-flesh-the-flash-2-sezon.html"
]
sem = asyncio.Semaphore(1000)
loop = asyncio.get_event_loop()
f = asyncio.wait([downlaod_html(d) for d in urls])
loop.run_until_complete(f)
0
Эксперт С++
 Аватар для Avazart
8488 / 6155 / 615
Регистрация: 10.12.2010
Сообщений: 28,683
Записей в блоге: 30
09.12.2016, 11:11
Ну так где тут цепочка взаимосвязанных запросов?
Типа авторизация - парсинг - запрос1 - парсинг +запрос2- ....
Ясное дело что если нужно делать по одному запросу то выглядит нормально, проблема возникает когда нужно делать параллельно "целые сессии".
0
2742 / 2341 / 620
Регистрация: 19.03.2012
Сообщений: 8,830
09.12.2016, 11:39
Avazart, это один из примеров. С сессиями тоже сильно большого треша не будет.
0
Эксперт С++
 Аватар для Avazart
8488 / 6155 / 615
Регистрация: 10.12.2010
Сообщений: 28,683
Записей в блоге: 30
09.12.2016, 13:49
В том то и дело что будет, это основной минус.

Наткнулся на интересное видео:
Конкурентность в Питоне с нуля.
Вживую. Доклад с PyCon US 2015 — ежегодной конференции python-разработчиков. Докладчик: Дэвид Бизли
0
Эксперт Python
 Аватар для АмигоСП
295 / 108 / 57
Регистрация: 07.12.2016
Сообщений: 209
09.12.2016, 15:01  [ТС]
Господа, я тут прерву немного вашу дискуссию))) Задам пару нубских вопросов) Вообщем немного начинаю разбираться с коннектами и эмитами) по крайней мере получилось вывести информацию о кол-ве данных выбираемого файла в GUI. Теперь такой вопрос: у меня несколько лейблов на ГУИ висят. практически все будут обновляться в процессе работы парсера, выводя промежуточную информацию(сколько осталось, сколько проверено, сколько подошло, сколько прокси забраковалось и т.п). Мне для каждого лейбла нужно присваивать свой pyqtSignal? Или есть какой то более правильный способ?
0
Эксперт С++
 Аватар для Avazart
8488 / 6155 / 615
Регистрация: 10.12.2010
Сообщений: 28,683
Записей в блоге: 30
09.12.2016, 15:13
Все зависит от того что из перечисленного вы используете.
Если только QN...A...Manager то можно просто через setText()
Если же потоки то необходима синхронизация, а ее можно достичь через сигнал/слот.
0
Эксперт Python
 Аватар для АмигоСП
295 / 108 / 57
Регистрация: 07.12.2016
Сообщений: 209
09.12.2016, 16:33  [ТС]
Цитата Сообщение от АмигоСП Посмотреть сообщение
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
    def authication(self):                            #Основная функция, из за которой зависает главное окно
        while not self.Email.empty():
            emailFull = self.Email.get()         # Получаем из очереди Queue Логины
            if not self.Proxy.empty():
                proxyFull = self.Proxy.get()     # Получаем из очереди Queue прокси(дальше идет проверка очереди и обновление
            elif self.checkReloadProxy != self.checkReloadMax:
                self.getFileProxy()
                proxyFull = self.Proxy.get()
                self.checkReloadProxy += 1
                self.label_7.setText("Proxy Обновился : " + str(self.checkReloadProxy) + '/' + str(self.checkReloadMax) + 'раз(а)')
            else:
                self.openFileProxy()
                #print('Загрузите новый файл м ПРОКСИ')
                self.findingError()
                proxyFull = self.Proxy.get()
                self.checkReloadProxy = 0
 
            auth = Grab()
            param = {
                'input': emailFull[:emailFull.find(':')]
            }
            proxies = proxyFull[:-1]
            auth.setup(post=param, proxy=proxies, proxy_type=self.proxyType, connect_timeout=self.TIME_LIMIT)
            try:
                auth.go(self.BaseURL)  # Здесь посылаем запрос с параметрами на нужный адрес
                #print(auth.url)
                AUTH = auth.response.unicode_body()
                self.emailRES.put((AUTH, emailFull))    #Если прокси сработал, то засовываем данные для дальнейшего парсинга в очередь
                self.label_13.setText("Проверено Email(ов) : " + str(self.Email.qsize()) + '/' + str(self.valueemail))
                self.progressCount += self.forProgress    # Это для прогрессбара в главном окне
                self.progressBar.setValue(self.progressCount)
 
            except Exception: # Если прокси не сработал, то используем счетчик и передаем информацию главному окну через лейбл_6
                self.errorProxy += 1
                self.label_6.setText("Неудача Proxy : " + str(self.errorProxy))
            
                self.Email.put(emailFull) # Добавляем логин заного в очередь
 
 
            self.label_4.setText('Осталось Proxy : ' + str(self.Proxy.qsize()) + '/' + str(self.valueproxy))
            self.Email.task_done()
            self.Proxy.task_done()
 
    def main(self): # На мейне законекчена кнопка старт - собираем все данные и запускаем потоки через treading
        self.getProxyType()
        self.TIME_LIMIT = self.timeOUTvalue.value()
        self.checkReloadMax = self.spinBox.value()
        VALUE_THREAD = self.thread_value.value()    #Практически все данные берутся из виджетов главного окна
 
        for _ in range(VALUE_THREAD):
            _ = threading.Thread(target=self.authication)
            _.start()
 
        self.Email.join()
        self.findingError() #В эту функцию передаются "сработавшие через прокси" логины для парсинга и в ней же записываются в файл
        self.emailRES.join()
        #self.file.close()
        self.progressBar.setValue(100)
        wdg = QMessageBox(self)
        wdg.setText('Обработка Завершена')
        wdg.exec_()
Через потоки получается. Надо тогда еще почитать про синхронизацию и слоты
0
Эксперт С++
 Аватар для Avazart
8488 / 6155 / 615
Регистрация: 10.12.2010
Сообщений: 28,683
Записей в блоге: 30
10.12.2016, 12:17
Цитата Сообщение от Avazart Посмотреть сообщение
Да действительно requests не подхватывает прокси SOCKS5 по чему-то
Видимо баг, если выставить заголовки то прокси начинают "подхватываться".

Bash
1
pip install -U requests[socks]
Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import re
import requests
 
 
def main():
    url = 'https://2ip.ru/'
    proxy_str = 'socks5://194.28.240.26:1080'
    proxies = {'http': proxy_str, 'https': proxy_str}
    headers = {}     # !!! 
    r = requests.get(url, headers= headers,proxies=proxies)
    r.raise_for_status()
 
    p = r'((\d{1,3}\.){3}\d{1,3})'
    m = re.search(p, r.text)
    if m:
        print("ip:",m.group(0))
    else:
        print("ip not found.")
 
 
if __name__ == "__main__":
    main()
1
Эксперт Python
 Аватар для АмигоСП
295 / 108 / 57
Регистрация: 07.12.2016
Сообщений: 209
11.12.2016, 15:36  [ТС]
Avazart, спасибо за подсказку. Так, теперь следующий момент всплыл)) По поводу зависания/отображения главного окна) Вроде бы получилось сделать, заработало. Использовал пример alex925(в начале темы выкладывал - через декоратор-отдельный поток). У меня главное окно запускает кнопкой старт функцию main(находящуюся уже в другом классе(QObject)). А там уже происходят всякие действия. Так вот, когда main отработает, в конце она выводит Qmessagebox стандартную с текстом, что все выполнилось и одна кнопка ОК. При нажатии на ОК, закрывается Qmessagebox(Qmessagebox.exec()), главное окно продолжает отображаться. Когда в линуксе запускал - то все было нормально. Запустив на Win_7, при нажатии ОК, винда говорит что возникли неполадки и предлагает отослать отчет. Наверняка я туплю, но вот где, пока еще не понимаю((

Добавлено через 5 часов 18 минут
Всё, со своим же вопросом последним разобрался). Пришлось через сигнал передавать в главное окно, что функция своё отработала. И в главном окне уже вызывать QMessageBox. Тогда в win7 никаких ошибок не вылетает. Странно, что на линуксе все нормально было без этого

Добавлено через 21 час 47 минут
Появился ещё один вопрос). Программа работает, ГУИ не зависает. Но решил попробовать добавить кнопку СТОП. Задумка в том, чтобы при нажатии прерывалась работа потоков. Оставшиеся данные из очереди queue записывались в файл. Возможно ли вообще такое сделать? А то про потоки(threading) кто чего пишет - что их невозможно вообще остановить
0
Эксперт С++
 Аватар для Avazart
8488 / 6155 / 615
Регистрация: 10.12.2010
Сообщений: 28,683
Записей в блоге: 30
11.12.2016, 15:50
Можно попробовать останавливать по флагу.

Добавлено через 2 минуты
Python
1
2
3
4
5
6
7
terminated_flag= False;
 
def authication(self):                            #Основная функция, из за которой зависает главное окно
        while not self.Email.empty() and not terminated_flag:
            emailFull = self.Email.get()         # Получаем из очереди Queue Логины
            if not self.Proxy.empty():
            #...

Python
1
terminated_flag= True
Т.е. в нужных местах (точках отмены/прерывания) расставлять проверки булевого флага и прерывать выполнение например через return;

Кстати GIL гарантирует атомарность переменных boolean?
1
Эксперт Python
 Аватар для АмигоСП
295 / 108 / 57
Регистрация: 07.12.2016
Сообщений: 209
11.12.2016, 20:00  [ТС]
Чего то не получается. Или я не правильно делаю, или одно из двух) Уже даже попробовал вынести в отдельную функцию - что при нажатии СТОП - очищается очередь queue с Email. И все равно Гуи продолжает работать, обновляя промежуточные значения. Значит получается и потоки работают(

Добавлено через 3 часа 5 минут
Всё, разобрался. Сам тупанул. забыл в конце task_done добавить для очереди, чтобы join() словил пустую queue
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
11.12.2016, 20:00
Помогаю со студенческими работами здесь

Как узнать margin-left любого элемента от главного окна окна браузера?
причем не важно какую вложенность имеет элемент сам элемент, т.е. в скольких контейнерах он бы не находился, нужно найти его marginLeft от...

Где и как правильно перерисовывать дочерние окна при изменении главного окна ?
Где и как правильно перерисовывать дочерние окна при изменении главного окна ? Про WM_SIZE знаю. Про остальное только догадываюсь.

Запуск второго окна перед стартом главного окна
необходимо запустить второе окно до старта основного окна и вызвать основное окно после завершения второго окна

Позиционирование дочернего окна относительно элемента главного окна
Всем привет. Подскажите пожалуйста, как можно сделать. У меня есть главное окно, на котором условно говоря расположен textbox, также у меня...

Переход из окна главного меню на другие окна приложения
Дали задание для курсового проекта Написать приложение на C# для Windows предназначенное для разгадывания ребусов у меня возникло три...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
39
Ответ Создать тему
Новые блоги и статьи
SDL3 для Web (WebAssembly): Обработчик клика мыши в браузере ПК и касания экрана в браузере на мобильном устройстве
8Observer8 02.02.2026
Содержание блога Для начала пошагово создадим рабочий пример для подготовки к экспериментам в браузере ПК и в браузере мобильного устройства. Потом напишем обработчик клика мыши и обработчик. . .
Философия технологии
iceja 01.02.2026
На мой взгляд у человека в технических проектах остается роль генерального директора. Все остальное нейронки делают уже лучше человека. Они не могут нести предпринимательские риски, не могут. . .
SDL3 для Web (WebAssembly): Вывод текста со шрифтом TTF с помощью SDL3_ttf
8Observer8 01.02.2026
Содержание блога В этой пошаговой инструкции создадим с нуля веб-приложение, которое выводит текст в окне браузера. Запустим на Android на локальном сервере. Загрузим Release на бесплатный. . .
SDL3 для Web (WebAssembly): Сборка C/C++ проекта из консоли
8Observer8 30.01.2026
Содержание блога Если вы откроете примеры для начинающих на официальном репозитории SDL3 в папке: examples, то вы увидите, что все примеры используют следующие четыре обязательные функции, а. . .
SDL3 для Web (WebAssembly): Установка Emscripten SDK (emsdk) и CMake для сборки C и C++ приложений в Wasm
8Observer8 30.01.2026
Содержание блога Для того чтобы скачать Emscripten SDK (emsdk) необходимо сначало скачать и уставить Git: Install for Windows. Следуйте стандартной процедуре установки Git через установщик. . . .
SDL3 для Android: Подключение Box2D v3, физика и отрисовка коллайдеров
8Observer8 29.01.2026
Содержание блога Box2D - это библиотека для 2D физики для анимаций и игр. С её помощью можно определять были ли коллизии между конкретными объектами. Версия v3 была полностью переписана на Си, в. . .
Инструменты COM: Сохранение данный из VARIANT в файл и загрузка из файла в VARIANT
bedvit 28.01.2026
Сохранение базовых типов COM и массивов (одномерных или двухмерных) любой вложенности (деревья) в файл, с возможностью выбора алгоритмов сжатия и шифрования. Часть библиотеки BedvitCOM Использованы. . .
SDL3 для Android: Загрузка PNG с альфа-каналом с помощью SDL_LoadPNG (без SDL3_image)
8Observer8 28.01.2026
Содержание блога SDL3 имеет собственные средства для загрузки и отображения PNG-файлов с альфа-каналом и базовой работы с ними. В этой инструкции используется функция SDL_LoadPNG(), которая. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru