Форум программистов, компьютерный форум, киберфорум
C# Windows Forms
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.58/40: Рейтинг темы: голосов - 40, средняя оценка - 4.58
управление сложностью
 Аватар для Почтальон
1693 / 1306 / 259
Регистрация: 22.03.2015
Сообщений: 7,545
Записей в блоге: 5

Многопоточность и доступ к элементам формы

17.05.2017, 21:22. Показов 8081. Ответов 21
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Приветствую, ребята, подскажите как и что лучше сделать.
Решил написать простенький парсер, в один поток работает все прекрасно, но страдает производительность, поэтому решил сделать многопоточную штуку. Есть несколько вопросов по реализации.
Если приложение будет многопоточным, то нужно будет всем потокам обращаться к разным записям одного списка адресов для парсинга. Создал свой класс, который обрабатывает страницы. Теперь стоит вопрос о том, как прикрутить многопоточность.
По сути, в потоке должен создаваться класс, который обрабатывает данные. Как эти данные обработать и передать на элементы управления? Например, как из потока получить запись из списка адресов, обработать ее в классе, и далее вывести результат обработки в другой элемент управления ?
0
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
17.05.2017, 21:22
Ответы с готовыми решениями:

Как получить доступ к элементам формы из другого обычного класса (не из второй формы)
Сабж. В гугле вся инфа только про доступ из другой формы, это я знаю. А вот как получить доступ из обычного модульного класса?

Доступ к элементам формы
Доброго времени суток. Не буду ходить вокруг да около. в общем, я занимаюсь программированием пару лет и вот решил освоить C#. До этого...

Доступ к элементам формы
Привет всем! Народ, такой вопрос. Можно ли организовать доступ к элементам формы через индексы? Например если они помещены в один...

21
Эксперт .NET
 Аватар для insite2012
5548 / 4311 / 1218
Регистрация: 12.10.2013
Сообщений: 12,371
Записей в блоге: 2
18.05.2017, 08:04
Цитата Сообщение от Почтальон Посмотреть сообщение
Как эти данные обработать и передать на элементы управления?
Стандартными методами. Через события. В классе-парсере свое событие, при необходимости со своим аргументом. Создаем класс-парсер, подписываемся на его событие и запускаем парсинг. Когда нужно, в классе-парсере бросаем событие, а в интерфейсе его обрабатываем (не забывая про маршалинг обращений в поток UI).

Добавлено через 8 часов 52 минуты
Почтальон, могу посоветовать один пример, которым сам пользуюсь. Тут могу говорить, что класс устарел, избыточен и прочее, но мне так нравится.
В общем, идея проста. Есть такой класс-BackgroundWorker. Я просто беру его и переопределяю его виртуальный метод OnDoWork, а в нем делаю всю работу. Удобств получается масса, когда не хочется заморачиваться с тасками и прочим, и когда их использование избыточно. Да и на .NET 4.0 работает, а для большинства фишек тасков нужен 4.5 и выше.
Чуть попозже сделаю пример, как это работает.
Если же нужна параллельность-то тут без тасков не обойтись, ну и PLINQ желательно использовать. Тоже удобная штука, но многое придется реализовывать самому.
1
управление сложностью
 Аватар для Почтальон
1693 / 1306 / 259
Регистрация: 22.03.2015
Сообщений: 7,545
Записей в блоге: 5
18.05.2017, 08:18  [ТС]
Заранее огромное спасибо !
0
Эксперт .NET
 Аватар для Rius
13122 / 7683 / 1675
Регистрация: 25.05.2015
Сообщений: 23,453
Записей в блоге: 14
18.05.2017, 09:57
C#
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
using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
 
namespace Postal
{
    public partial class Form1 : Form
    {
        private CancellationTokenSource mToken;
        private TaskScheduler mScheduler;
 
        public Form1()
        {
            InitializeComponent();
        }
 
        private async void buttonStart_Click(object sender, EventArgs e)
        {
            this.buttonStart.Enabled = false;
            this.buttonStop.Enabled = true;
            this.mToken = new CancellationTokenSource();
            this.mScheduler = TaskScheduler.FromCurrentSynchronizationContext();
 
            try
            {
                await Task.Factory.StartNew(o => this.Scan((CancellationToken)o),
                    this.mToken.Token,
                    this.mToken.Token,
                    TaskCreationOptions.LongRunning,
                    TaskScheduler.Default);
            }
            catch (OperationCanceledException)
            {
            }
            catch (AggregateException)
            {
            }
 
            this.buttonStart.Enabled = true;
            this.buttonStop.Enabled = false;
        }
 
        private void Scan(CancellationToken token)
        {
            string[] addresses = new string[] { "1", "2", "3", "4", "5", "6", "8", "9", "10" };
 
            addresses.AsParallel()
                .WithCancellation(token)
                .ForAll(x => this.Parse(token, x));
        }
 
        private void buttonStop_Click(object sender, EventArgs e)
        {
            this.mToken.Cancel();
        }
 
        private void Parse(CancellationToken token, string address)
        {
            this.ShowProgress(token, String.Format("{0} - {1}{2}", address, "start", Environment.NewLine));
            // Длительная операция
            token.WaitHandle.WaitOne(1000);
            this.ShowProgress(token, String.Format("{0} - {1}{2}", address, "end", Environment.NewLine));
        }
 
        private void ShowProgress(CancellationToken token, string message)
        {
            Task.Factory.StartNew(() => this.richTextBox1.AppendText(message), token, TaskCreationOptions.None, this.mScheduler);
        }
    }
}
0
управление сложностью
 Аватар для Почтальон
1693 / 1306 / 259
Регистрация: 22.03.2015
Сообщений: 7,545
Записей в блоге: 5
18.05.2017, 19:57  [ТС]
Rius, извиняюсь, но что-то туплю.
Допустим есть код:
C#
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
public partial class MainForm : Form
{
 //главная функция программы
 public MainForm()
        {
            InitializeComponent();                                          
        }
 //кнопка запуска потока
 private void btnStartThread_Click(object sender, EventArgs e)
        {
            //создание отдельного потока
            Thread potok1 = new Thread(start_thread_parse);
            // завершить поток при завершении основного потока (объявлять, если точно знаете, что вам это нужно,
            //иначе поток завершится не выполнив свою работу до конца)
            potok1.IsBackground = true;
            //запуск потока
            potok1.Start();
        }
//процедура для выполнения потока
        void start_thread_parse()
        {
            //объявляем класс переменной для парсинга
            //собственный класс, который обрабатывает данные на странице
            MyParserClass parse_data = new MyParserClass();
            //checkLBUrlParse (checkedListBox) содержит список адресов, которые нужно обработать
            for (int ind_rec = 0; ind_rec < checkLBUrlParse.Items.Count; ind_rec++)
            {                              
                //проверяем установлена ли галка для обработки
                if (checkLBUrlParse.GetItemChecked(ind_rec))
                {
                    //вызываем метод класса для парсинга
                    parse_data.ParseUrl(checkLBUrlParse.Items[ind_rec].ToString());
                    //снимаем галку посещения
                    checkLBUrlParse.SetItemChecked(ind_rec, false);
                    //делаем паузу в работе потока
                    Thread.Sleep((int)numParseInterval.Value * 1000);
                }                             
            }
        }
Т.е. по сути в потоке выполняется обработка списка адресов, а вот как обратиться к элементам формы корректно, что-то не могу (инфу читал, в основном в примерах простой текстовый компонент используется, и то, только запись данных, но не чтение., а мне по сути нужно и запись и чтение (чтобы ставить и снимать галки в списке)
Думаю что по аналогии можно сделать и для вывода данных из потока в DataGridView.
Как вот такое секое можно реализовать ?
0
Эксперт .NET
 Аватар для Rius
13122 / 7683 / 1675
Регистрация: 25.05.2015
Сообщений: 23,453
Записей в блоге: 14
18.05.2017, 20:24
И чтение, и изменение данных в контролах UI из потока всегда надо синхронизировать.
В общем случае создаётся некий код. Оборачивается в нечто (делегат, например), что передаётся в поток UI, в очередь сообщений окна. Там из очереди выуживается это нечто, и вызывается исходный код.
Пример у меня в 69 строке. Тут ещё несколько: Скорость работы при использовании UpdateProgressDelegate для отображения прогресса
Там же во 2 варианте Скорость работы при использовании UpdateProgressDelegate для отображения прогресса приведён устаревший, но всё равно работающий метод: сохранение данных в одном месте, к которому доступ является потокобезопасным. У одного потока на запись, у другого на чтение; либо запись и чтение разграничены семафорами.

DataGridView обычно биндится к какому-то источнику данных. Вот в нём и нужно менять данные. Если источник от DataGridView отключен, то если это DataTable, например, его можно менять прямо в другом потоке. Если же подключён - только в потоке UI.
0
управление сложностью
 Аватар для Почтальон
1693 / 1306 / 259
Регистрация: 22.03.2015
Сообщений: 7,545
Записей в блоге: 5
18.05.2017, 20:37  [ТС]
Поиском находил тот топик, но что-то вникнуть не смог. Как я понял, там устанавливаются значения простым элементам. Я вот что-то никак не догоню, как хотя бы прочитать данные с контрола (из списка адресов) и дальше с ними работать в потоке
0
Эксперт .NET
 Аватар для Rius
13122 / 7683 / 1675
Регистрация: 25.05.2015
Сообщений: 23,453
Записей в блоге: 14
18.05.2017, 20:42
А смысл считывать значения пользователького ввода при уже работающем потоке? Данные надо подготовить до его запуска, потом запустить и дождаться результата.
В редких случаях реальной надобности тот самый второй вариант в нескольких вариациях. Сохранение в простом объекте, неравенство null которого проверяет поток. Сохранение данных в потокобезопасной очереди. В общем-то та же самая синхронизация доступа к данным, только уже в другом направлении, попроще.
0
управление сложностью
 Аватар для Почтальон
1693 / 1306 / 259
Регистрация: 22.03.2015
Сообщений: 7,545
Записей в блоге: 5
18.05.2017, 21:14  [ТС]
Цитата Сообщение от Rius Посмотреть сообщение
А смысл считывать значения пользователького ввода при уже работающем потоке?
Хотел в потоке получать значение списка, передать его в поток для обработки, и результат работы потока вывести в таблицу.
0
Эксперт .NETАвтор FAQ
 Аватар для Storm23
10427 / 5157 / 1825
Регистрация: 11.01.2015
Сообщений: 6,226
Записей в блоге: 34
18.05.2017, 21:54
Цитата Сообщение от Почтальон Посмотреть сообщение
Я вот что-то никак не догоню, как хотя бы прочитать данные с контрола (из списка адресов) и дальше с ними работать в потоке
Вам не нужно читать список адресов из контрола. Список адресов должен храниться в модели данных (в вашем простейшем случае в List<URL>), а контрол и поток должны работать с моделью.
C#
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
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Threading;
using System.Windows.Forms;
 
namespace WindowsFormsApplication371
{
    public partial class Form1 : Form
    {
        //data model
        List<URL> urls = new List<URL>();
 
        public Form1()
        {
            InitializeComponent();
 
            //genarate random urls
            for (int i = 0; i < 1000; i++)
                urls.Add(new URL {Address = "http://a" + i + ".com"});
 
            //bind urls to clb
            (clbURLs as ListBox).DataSource = urls;
 
            //handle check state changes
            clbURLs.ItemCheck += (o, e) => urls[e.Index].IsChecked = e.NewValue == CheckState.Checked;
        }
 
        private void btStart_Click(object sender, EventArgs e)
        { 
            new Thread(Work) { IsBackground  = true}.Start();
            btStart.Enabled = false;
        }
 
        private void Work()
        {
            //enumerate checked urls
            foreach(var url in urls.Where(u=>u.IsChecked))
            try
            {
                //check availability
                new WebClient().OpenRead(url.Address);
                url.Result = "Available";
                //update clb
                clbURLs.Invalidate();
            }
            catch
            {
                url.Result = "Is not available";
                clbURLs.Invalidate();
            }
 
            //enable button
            Invoke((MethodInvoker)(()=>{btStart.Enabled = true;}));
        }
    }
 
    class URL
    {
        public string Address { get; set; }
        public bool IsChecked { get; set; }
        public string Result { get; set; }
 
        public override string ToString()
        {
            return Address + " " + Result;
        }
    }
}
Вложения
Тип файла: zip WindowsFormsApplication371 (4).zip (58.9 Кб, 23 просмотров)
1
управление сложностью
 Аватар для Почтальон
1693 / 1306 / 259
Регистрация: 22.03.2015
Сообщений: 7,545
Записей в блоге: 5
19.05.2017, 12:35  [ТС]
Т.е. по сути в каждом потоке нужно будет использовать свой список адресов, вместо использования общего ? Так конечно более логично выглядит. Но как быть тогда с выводом данных от каждого потока в DataGridView, не подскажете ?
0
Эксперт .NET
 Аватар для Rius
13122 / 7683 / 1675
Регистрация: 25.05.2015
Сообщений: 23,453
Записей в блоге: 14
19.05.2017, 12:41
Можно и общий. Зависит от задачи. Вы с ней определились уже?

Добавлено через 2 минуты
Почтальон,
Нужно обработать список адресов в независимых потоках и получить результат?
Или нужно запустить кучу потоков, и манипулировать данными для них уже в ходе работы?
0
Эксперт .NETАвтор FAQ
 Аватар для Storm23
10427 / 5157 / 1825
Регистрация: 11.01.2015
Сообщений: 6,226
Записей в блоге: 34
19.05.2017, 12:49
Цитата Сообщение от Почтальон Посмотреть сообщение
Т.е. по сути в каждом потоке нужно будет использовать свой список адресов, вместо использования общего ?
Вовсе нет. Из исходного списка нужно взять отмеченные элементы, и сформировать из них очередь. А затем потоки будут брать адреса из очереди по ... очереди. Паттерн Producer-Consumer.
В качестве очереди можно использовать либо обычную Queue<URL> (но тогда нужен lock при доступе), либо ConcurrentQueue<URL>, либо сделать ленивый потокобезопасный итератор поверх List<URL> (я бы так и сделал, но вам такие сложности я думаю не нужны).
Цитата Сообщение от Почтальон Посмотреть сообщение
Но как быть тогда с выводом данных от каждого потока в DataGridView, не подскажете ?
Точно так же. Создаете список результатов, потоки заносят туда свои результаты. DataGridView - просто биндится к списку и время от времени обновляется, что показать юзеру результаты.
Хотя я бы посоветовал не делать отдельный список результатов, а результат сохранять в исходном объекте URL (собственно в моем примере так и сделано).
0
управление сложностью
 Аватар для Почтальон
1693 / 1306 / 259
Регистрация: 22.03.2015
Сообщений: 7,545
Записей в блоге: 5
19.05.2017, 13:26  [ТС]
Цитата Сообщение от Rius Посмотреть сообщение
Нужно обработать список адресов в независимых потоках и получить результат?
Думаю что так будет более эффективно. У меня есть общий список адресов(заполняется из файла и ставится галка), потом идет обход этого списка, если галка стоит - значит нужно обработать адрес(по умолчанию при загрузке из файла выставляются все галки), как только обработали адрес - галка снимается. Вот у меня задумка такая, что в несколько потоков обращаться к этому списку и брать требуемый адрес на обработку. Доступ к общему списку из потоков нужно делать безопасно, чтобы не было "задвоения" обработки. Далее, как только метод класс обработал адрес, его результаты добавлялись в таблицу (выводилась спарсенная информация). У меня все прекрасно работало, когда все реализовал в главном классе, т.е. по сути в главном потоке. Но вот решил переделать под многопоточность
Цитата Сообщение от Storm23 Посмотреть сообщение
Точно так же. Создаете список результатов, потоки заносят туда свои результаты. DataGridView - просто биндится к списку и время от времени обновляется, что показать юзеру результаты.
Скорее всего так и нужно будет делать, в потоке заполнять список результатов, и периодически их выкидывать на DataGridView
0
Эксперт .NET
 Аватар для Rius
13122 / 7683 / 1675
Регистрация: 25.05.2015
Сообщений: 23,453
Записей в блоге: 14
19.05.2017, 16:09
Почтальон, можно так:
Вложения
Тип файла: zip Postal.zip (20.5 Кб, 27 просмотров)
1
управление сложностью
 Аватар для Почтальон
1693 / 1306 / 259
Регистрация: 22.03.2015
Сообщений: 7,545
Записей в блоге: 5
19.05.2017, 17:36  [ТС]
Rius, ок, спасибо большое, покурю примерчик
0
управление сложностью
 Аватар для Почтальон
1693 / 1306 / 259
Регистрация: 22.03.2015
Сообщений: 7,545
Записей в блоге: 5
21.05.2017, 21:51  [ТС]
Попробовал сделать вот таким образом:
C#
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
public partial class MainForm : Form
{
//источник данных для списка адресов парсинга
//список класса URL где находится список адресов;
List<URL> urls_list = new List<URL>();
public MainForm()
{
            InitializeComponent();
}
 
//обработчик кнопки выбора файла для обработки
        private void btnGetUrlsFromFile_Click(object sender, EventArgs e)
        {
            //выбираем файл для обработки
            if (openFileDialog.ShowDialog() == DialogResult.OK)
            {
                textbPathToFile.Text = openFileDialog.FileName;
                //читаем данные из файла
                XmlTextReader reader = new XmlTextReader(textbPathToFile.Text);
                //обрабатываем данные файла
                while (reader.Read())
                {
                    if (reader.Name == "loc")
                    {
                        reader.Read();
                        //создаем класс для хранения адреса
                        URL tmp_url = new URL();
                        tmp_url.Address = reader.Value;
                        tmp_url.IsChecked = true; //почему-то в список не устанавливается
                        //добавляем полученный адрес в список модели данных                
                        urls_list.Add(tmp_url);
                        reader.Read();
                    }
                }
                //присваиваем список на форме
                checkLBUrlParse.DataSource = urls_list;
            }
        }
//кнопка запуска потока
        private void btnStartThread_Click(object sender, EventArgs e)
        {
            //создание отдельного потока
            Thread potok1 = new Thread(start_thread_parse);
            // завершить поток при завершении основного потока (объявлять, если точно знаете, что вам это нужно,
            //иначе поток завершится не выполнив свою работу до конца)
            potok1.IsBackground = true;
            //запуск потока
            potok1.Start();
        }
//процедура для выполнения потока
        void start_thread_parse()
        {
            //объявляем класс переменной для парсинга   
            PageParser parse_data = new PageParser();
            //перебираем список
            for (int ind_rec = 0; ind_rec < urls_list.Count; ind_rec++)
            {
                //проверяем посещение сайта
                //если галка не установлена, тогда нужно спарсить
                if (!checkLBUrlParse.GetItemChecked(ind_rec))
                {
                    parse_data.ParseUrl(urls_list[ind_rec].ToString());//парсим данные
                    //и вот тут нужно
                    //ставить галку посещения*********
                    //получаем спарсенные данные
                    string name_comp = parse_data.name_company; //наименование компании
//и вот тут нужно уже будет выводить данные в dataGridView
                    //делаем паузу в работе потока
                    Thread.Sleep(15000);
                }
            }
        }
//класс для хранения адреса
    class URL
    {
        public string Address { get; set; }
        public bool IsChecked { get; set; }
 
        public override string ToString()
        {
            return Address;
        }
    }
}
Появилось несколько вопросов.
Вот хотелось бы поинтересоваться, может не тот контейнер (List) использую для хранения URL ? Я имею ввиду, как проставить галку и отразить этот признак в urls_list (это же по сути список, с которым работает поток и будут работать остальные другие) при окончании получении ответных данных?
0
Эксперт .NETАвтор FAQ
 Аватар для Storm23
10427 / 5157 / 1825
Регистрация: 11.01.2015
Сообщений: 6,226
Записей в блоге: 34
21.05.2017, 22:19
Цитата Сообщение от Почтальон Посмотреть сообщение
C#
1
2
3
4
5
6
7
8
9
10
11
for (int ind_rec = 0; ind_rec < urls_list.Count; ind_rec++)
{
 //проверяем посещение сайта
 //если галка не установлена, тогда нужно спарсить
 if (!checkLBUrlParse.GetItemChecked(ind_rec))
 {
   parse_data.ParseUrl(urls_list[ind_rec].ToString());//парсим данные
   string name_comp = parse_data.name_company; //наименование компании
   Thread.Sleep(15000);
 }
}
Здесь вы не должны работать с checkLBUrlParse. Вообще забудьте про него. Ваша программа должна работать без него. CheckListBox - просто для отображения списка пользователю, больше ни для чего.
0
управление сложностью
 Аватар для Почтальон
1693 / 1306 / 259
Регистрация: 22.03.2015
Сообщений: 7,545
Записей в блоге: 5
22.05.2017, 08:24  [ТС]
Storm23, я это понимаю, почитал топик о разделении данных и интерфейса (очень поучительно )
У меня как раз ступор в том, что как из потока "безопасно" поставить метку в контейнере urls_list, чтобы потом эта метка отобразилась на checkLBUrlParse, вот хоть убейте, не отдупляю
0
Эксперт .NET
 Аватар для Rius
13122 / 7683 / 1675
Регистрация: 25.05.2015
Сообщений: 23,453
Записей в блоге: 14
22.05.2017, 08:25
Почтальон, в моём примере что, совсем ничего не понятно?
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
22.05.2017, 08:25
Помогаю со студенческими работами здесь

Доступ к элементам формы навигации
Здравствуйте. Я только начинаю осваивать формы навигации. Прошу помочь. Имеется форма навигации, элемент навигации содержит две кнопки...

Динамический доступ к элементам формы
Доброго времени суток уважаемые! Решил попробовать сделать одну программку, в которой более 100 параметров (Properties.Settings),...

Доступ к элементам формы из класса
Есть главное окно WPF - Window1 Я написал public accessor для изменения контрола /// Изменение прогресс бара public void...

Доступ к элементам другой формы
Добрый день! подскажите, как можно осуществить доступ к элементам другой формы. грубо говоря, мне надо из 2-й формы обновить содержимое...

Публичный доступ к элементам формы
подскажите пожалуйста просто способ, как сделать элементы на форме доступными в классе...


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

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Новые блоги и статьи
SDL3 для Web (WebAssembly): Идентификация объектов на Box2D v3 - использование userData и событий коллизий
8Observer8 02.03.2026
Содержание блога Финальная демка в браузере. Итоговый код: finish-collision-events-sdl3-c. zip https:/ / www. cyberforum. ru/ blog_attachment. php?attachmentid=11680&amp;d=1772460536 Одним из. . .
Реалии
Hrethgir 01.03.2026
Нет, я не закончил до сих пор симулятор. Эта задача сложнее. Не получилось уйти в плавсостав, но оно и к лучшему, возможно. Точнее получалось - но сварщиком в палубную команду, а это значит, в моём. . .
Ритм жизни
kumehtar 27.02.2026
Иногда приходится жить в ритме, где дел становится всё больше, а вовлечения в происходящее — всё меньше. Плотный график не даёт вниманию закрепиться ни на одном событии. Утро начинается с быстрых,. . .
SDL3 для Web (WebAssembly): Сборка библиотек: SDL3, Box2D, FreeType, SDL3_ttf, SDL3_mixer и SDL3_image из исходников с помощью CMake и Emscripten
8Observer8 27.02.2026
Недавно вышла версия 3. 4. 2 библиотеки SDL3. На странице официальной релиза доступны исходники, готовые DLL (для x86, x64, arm64), а также библиотеки для разработки под Android, MinGW и Visual Studio. . . .
SDL3 для Web (WebAssembly): Реализация движения на Box2D v3 - трение и коллизии с повёрнутыми стенами
8Observer8 20.02.2026
Содержание блога Box2D позволяет легко создать главного героя, который не проходит сквозь стены и перемещается с заданным трением о препятствия, которые можно располагать под углом, как верхнее. . .
Конвертировать закладки radiotray-ng в m3u-плейлист
damix 19.02.2026
Это можно сделать скриптом для PowerShell. Использование . \СonvertRadiotrayToM3U. ps1 <path_to_bookmarks. json> Рядом с файлом bookmarks. json появится файл bookmarks. m3u с результатом. # Check if. . .
Семь CDC на одном интерфейсе: 5 U[S]ARTов, 1 CAN и 1 SSI
Eddy_Em 18.02.2026
Постепенно допиливаю свою "многоинтерфейсную плату". Выглядит вот так: https:/ / www. cyberforum. ru/ blog_attachment. php?attachmentid=11617&stc=1&d=1771445347 Основана на STM32F303RBT6. На борту пять. . .
Камера Toupcam IUA500KMA
Eddy_Em 12.02.2026
Т. к. у всяких "хикроботов" слишком уж мелкий пиксель, для подсмотра в ESPriF они вообще плохо годятся: уже 14 величину можно рассмотреть еле-еле лишь на экспозициях под 3 секунды (а то и больше),. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru