void SpreadSheet::init()
{
currentSheet = sheet1;
project = new QSProject( this, "spreadsheet_project" );
interpreter = project->interpreter();
QSInputDialogFactory *fac = new QSInputDialogFactory; /* toto je potreba kvuli input dialog framework - aby si skript mohl vytvaret UI */
interpreter->addObjectFactory( fac );
project->addObject( new SheetInterface( sheet1, this, "sheet1" ) );
project->QaddObject( new SheetInterface( sheet2, this, "sheet2" ) );
setupSheet( sheet1 );
setupSheet( sheet2 );
project->load( "spreadsheet.qsa" );
connect( project, SIGNAL( QprojectEvaluated() ),
project, SLOT( Qsave() ) );
}
4.3.1 Umožnit uživateli vytvářet a editovat skriptyOtevřít QSA Workbenchvytvořit/editovat skript.
Definovat makro.
void AddScriptDialog::addScript()
{
QSInterpreter *script = ( (SpreadSheet*) parent() )->interpreter;
QString func = comboFunction->currentText();
if ( script->functions().findIndex( func ) == -1 ) {
QString msg = tr( "The function <b>%1</b> doesn't exist. "
"Do you want to add it?" ).arg( func );
if ( QMessageBox::information( 0, tr( "Add Function" ), msg,
tr( "&Yes" ), tr( "&No" ),
"", 0, 1 ) == 0 ) {
QSScript *sc = script->project()->script( "main.qs" );
if( !sc )
sc = script->project()->createScript( "main.qs" );
sc->addFunction( func );
( (SpreadSheet*) parent() )->showFunction( sc, func );
}
}
emit newScript( func, editName->text(), *labelPixmap->pixmap() );
accept();
}
void SpreadSheet::openIDE()
{
#ifndef QSA_NO_IDE
// open the QSA Workbench
if ( !spreadsheet_ide ) spreadsheet_ide = new QSWorkbench( project, this, "qside" );
spreadsheet_ide->open();
#else
QMessageBox::information( this, "Disabled feature",
"QSA Workbench has been disabled. Reconfigure to enable",
QMessageBox::Ok );
#endif
}
4.3.4 Přidávání a editace maker void AddScriptDialog::init()
{
// List all global functions of the project
QSProject *project = ( (SpreadSheet*) parent() )->project;
comboFunction->insertStringList( project->interpreter()->functions() );
}
Pokud v tomto dialogu skriptující uživatel odsouhlasí jméno funkce, spustí se
následující kód:
void AddScriptDialog::addScript()
{
QSInterpreter *script = ( (SpreadSheet*) parent() )->interpreter;
QString func = comboFunction->currentText();
if ( script->functions().findIndex( func ) == -1 ) {
QString msg = tr( "The function <b>%1</b> doesn't exist. "
"Do you want to add it?" ).arg( func );
if ( QMessageBox::information( 0, tr( "Add Function" ), msg,
tr( "&Yes" ), tr( "&No" ),
"", 0, 1 ) == 0 ) {
QSScript *sc = script->project()->script( "main.qs" );
if( !sc )
sc = script->project()->createScript( "main.qs" );
sc->addFunction( func );
( (SpreadSheet*) parent() )->showFunction( sc, func );
}
}
emit newScript( func, editName->text(), *labelPixmap->pixmap() );
accept();
}
Na konci je vyslán signal newScript(). Tato funkce vytvoří akci která bude spojena
s makrem a přidá položku do menu a tlačítko do toolbaru. Dále je k signálu
activated() připojen k runScript(). Aby bylo jasné kterou funkci bude toto makro
(akce) volat, je akce a její asociovaná funkce vložena do scripts map:
void SpreadSheet::addScript( const QString &function, const QString &name, const QPixmap &pixmap )
{
// Add a new action for the script
QAction *a = new QAction( name, pixmap, name, 0, this, name.latin1() );
a->addTo( scriptsToolbar );
a->addTo( scriptsMenu );
// associate the action with the function name
scripts.insert( a, function );
connect( a, SIGNAL( activated() ), this, SLOT( runScript() ) );
}
Pokud nechceme, aby uživatel musel po každém spuštění skriptu v QSA Workbench
klikat na "Run", je možné použít následující přístup. V předchozím kódu došlo k
asociaci makra (globální funkce) a akce. Když uživatel vyvolá akci, dojde
ke spuštění runScript() a je nutné zjistit,
která funkce se má pro danou akci spustit (a pak ji pomocí
QSInterpreter::call() spustit). Každý slot v Qt může zavolat sender()
(který je implementován v hlavním Qt objektu QObject) aby zjistil jaká action
vyvolala slot. Můžeme přetypovat sender() na QAction (v tomto případě víme, že
je to QAction) a pak tento pointer vyhledat v mapě scripts.
void SpreadSheet::runScript()
{
// find the function which has been associated with the activated
// action (the action is the sender())
QString s = *scripts.find( (QAction*)sender() );
// and call that function
project->commitEditorContents();
interpreter->call( s, QValueList<QVariant>() );
}
5. Zpřístupněnní C++ objektů skriptům napsaným v QSA
class MyObject : public QObject
{
Q_OBJECT
public:
MyObject( ... );
void aNonScriptableFunction();
public slots: // these functions (slots) will be available in Qt Script
void calculate( ... );
void setEnabled( bool enabled );
bool isEnabled() const;
private:
....
};
V tomto příkladu budou poslední tři metody viditelné pro QSA skript, protože jsou
definované jako sloty, ale metoda aNonScriptableFunction() nikoliv.var obj = new MyObject; obj.setEnabled( true ); debug( "obj is enabled: " + obj.isEnabled() );Ovšem pokud bychom toto chtěli nechat dělat programátora skriptu "přímo", tj:
var obj = new MyObject; obj.enabled = true; debug( "obj is enabled: " + obj.enabled );musíme zajistit (opět prostředky Meta Object Systemu), aby Qt skript měl přistup k property enabled. Aby bylo toto možné, je potřeba definovat properties v potomku třidy QObject způsobem ukázaným v následujícím příkladu - deklarovat property enabled typu bool, který bude používat funkci setEnabled(bool) jako setter a isEnabled() jako getter.
class MyObject : public QObject
{
Q_OBJECT
// define the enabled property
Q_PROPERTY( bool enabled WRITE setEnabled READ isEnabled )
public:
MyObject( ... );
void aNonScriptableFunction();
public slots: // these functions (slots) will be available in Qt Script
void calculate( ... );
void setEnabled( bool enabled );
bool isEnabled() const;
private:
....
};
5.3 Zpřístupnění properties C++ třidy
class MyObject : public QObject
{
Q_OBJECT
// define the enabled property
Q_PROPERTY( bool enabled WRITE setEnabled READ isEnabled )
public:
MyObject( ... );
void aNonScriptableFunction();
public slots: // these functions (slots) will be available in Qt Script
void calculate( ... );
void setEnabled( bool enabled );
bool isEnabled() const;
signals: // the signals
void enabledChanged( bool newState );
private:
....
};
Programátor skriptu pak může udělat
function enabledChangedHandler( b )
{
debug( "state changed to: " + b );
}
function init()
{
var obj = new MyObject;
// connect a script function to the signal
connect( obj, "enabledChanged(bool)", this, "enabledChangedHandler" );
obj.enabled = true;
debug( "obj is enabled: " + obj.enabled );
}
čímž dosáhl toho že kdykoliv je vyvolána metoda enabledChanged()
objektu MyObject tak je zavolána funkce
enabledChangedHander() - naprosto stejným mechanismem
jako by tomu bylo v Qt.

var inputCol = 1;
var startRow = 1;
var endRow = 1;
var outputCol = 1;
if ( Application.sheet1.numSelections > 0 ) {
var sel = Application.sheet1.selection( 0 );
inputCol = sel.x + 1;
outputCol = inputCol + 1;
startRow = sel.y + 1;
endRow = sel.bottom + 1;
}
Vytvoříme dialogbox (bez vysvětlování, je to zřejmé i bez znalosti pŕesné syntaxe):
d = new Dialog;
d.caption = "Settings for Euro Converter";
d.okButtonText = "Calculate";
d.cancelButtonText = "Cancel";
var g = new GroupBox;
g.title = "Conversion Range:";
d.add( g );
var spinColumn = new SpinBox;
spinColumn.label = "Column:";
spinColumn.minimum = 1;
spinColumn.maximum = 100;
spinColumn.value = inputCol;
g.add( spinColumn );
var spinStartRow = new SpinBox;
spinStartRow.label = "Start at Row:";
spinStartRow.minimum = 1;
spinStartRow.maximum = 100;
spinStartRow.value = startRow;
g.add( spinStartRow );
var spinEndRow = new SpinBox;
spinEndRow.label = "End at Row:";
spinEndRow.minimum = 1;
spinEndRow.maximum = 100;
spinEndRow.value = endRow;
g.add( spinEndRow );
var spinOutput = new SpinBox;
spinOutput.label = "Output Column:";
spinOutput.minimum = 1;
spinOutput.maximum = 100;
spinOutput.value = outputCol;
g.add( spinOutput );
d.newColumn();
var g = new GroupBox;
g.title = "Conversion Range:";
d.add( g );
var radioUSD = new RadioButton;
radioUSD.text = "USD";
radioUSD.checked = true;
g.add(radioUSD);
var radioYEN = new RadioButton;
radioYEN.text = "YEN";
g.add(radioYEN);
var radioNOK = new RadioButton;
radioNOK.text = "NOK";
g.add(radioNOK);
Pak v QSA Workbenchi pomocí tlačítka Call function
můžeme definovat kód který se má vykonat při stisknutí tlačítka OK v tomto
dialogu. var divisor;
if( radioUSD.checked )
divisor = 0.930492;
else if( radioYEN.checked )
divisor = 0.007677;
else if ( radioNOK.checked )
divisor = 0.133828;
Další blok kódu inicializuje proměnné ohraničující buňky ve kterých jsou údaje
určené k převodu
inputCol = spinColumn.value - 1;
outputCol = spinOutput.value - 1;
startRow = spinStartRow.value - 1;
endRow = spinEndRow.value - 1;
Pokud je rozash neplatný, skript ohlásí chybu
if ( endRow < startRow ) {
MessageBox.critical( "Cannot calculate!", "Error" );
return;
}
Poslední blok provede aktuální výpočet
for ( var i = startRow; i <= endRow; ++i ) {
var input = Application.sheet1.text( i, inputCol );
Application.sheet1.setText( i, outputCol,
Math.round( input / divisor * 100 ) / 100 );
}
A pak už lze v aplikaci vyplnit do buněk čísla, kliknout na ikonku našeho skriptu
který jsme právě vytvořili a nechat hodnoty převést do jiné měny. Tuto konverzi
v původní spreadsheetové aplikaci udělal kompletně skript, který si koncový
uživatel do aplikace naprogramoval.