Page 1 of 1

Пример с потоком

PostPosted: 26 Jun 2016, 09:22
by mkornevich3
Создайте пожалуйста пример: В окне многострочное поле и кнопка при нажатии на которую запускается поток который загружает с гугла главную страницу и вставляет в многострочное поле. Главное чтоб вставка в поле происходила в потоке.

Re: Пример с потоком

PostPosted: 28 Jun 2016, 20:50
by WxMaper
Code:
<?php

class WebWorker extends QObject {
    public $signals = [
        "finished(string)"
    ];

    public function __construct() {
        parent::__construct();
    }
    
    public function get_slot($sender, $url) {
        sleep(5); // для наглядности
        
        $content = file_get_contents($url);
        $this->emit("finished(string)", [ $content ]);
    }
    
    public function get($url) {
        sleep(5); // для наглядности
        
        $content = file_get_contents($url);
        $this->emit("finished(string)", [ $content ]);
    }
}

class MainWindow extends QWidget {
    private $worker;
    private $thread;
    
    private $textEdit;
    private $lineEdit;
    private $button;
    
    public $signals = [
        "getContents(string)"
    ];

    public function __construct() {
        parent::__construct();
        $this->initComponents();
    }
    
    private function initComponents() {
        $this->thread = new QThread;
        $this->thread->start();
        
        $this->worker = new WebWorker;
        $this->worker->moveToThread($this->thread);
        
        // создаём виджеты
        $this->textEdit = new QTextEdit;
        
        $this->lineEdit = new QLineEdit;
        $this->lineEdit->text = "http://phpqt.ru/";
        
        $this->button = new QPushButton("Get HTML");
        
        // vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
        // vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
        /** Вся проблема в том, что on*-сигналы всегда выполняются в текущем потоке,
            поэтому такой код:
           
            $this->button->onClicked = function() {
                $this->worker->get($this->lineEdit->text);
            };
        
            хоть и является рабочим, но будет замораживать форму.
            Связь событий для работы с потоками нужно создавать через функцию connect()
            
            Это пример использования сигнала onClicked() для передачи строкового параметра
            объекту, находящемуся в другом потоке: при срабатывании сигнала onClicked(),
            мы генерируем новый сигнал с нужными параметрами,
            который был зарегистрирован в переменной $signals. (эта переменная брабатывается движком)
        */
        
        $this->button->onClicked = function() {
            $this->emit("getContents(string)", [ $this->lineEdit->text ]);
        };
        
        // затем мы просто соединяем нужные сигналы со слотами через функцию connect()
        connect($this->worker, SIGNAL("finished(string)"),
                $this, SLOT("finished_slot(string)"));
                
        connect($this, SIGNAL("getContents(string)"),
                $this->worker, SLOT("get_slot(string)"));
                
        // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        
        // создаём компоновщик и кидаем на него виджеты
        $this->layout = new QVBoxLayout;
        $this->layout->addWidget($this->textEdit);
        $this->layout->addWidget($this->lineEdit);
        $this->layout->addWidget($this->button);
    }
    
    public function finished_slot($sender, $content) {
        pre($content); 
    }
}

$mainWindow = new MainWindow;
$mainWindow->show();

qApp::exec();
Этот код не будет работать в снапшоте PQBuilder 0.5.3 от 23.06.2016 (обнаружен баг)
Но будет работать в версии 0.5.2. В следующих версиях/снапшотах баг будет исправлен, на этой неделе постараюсь выложить исправленную сборку.