Qt Installer Framework 不覆盖现有安装的解决方法 [英] Workaround for Qt Installer Framework not overwriting existing installation

查看:20
本文介绍了Qt Installer Framework 不覆盖现有安装的解决方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这个问题是关于 Qt Installer Framework 2.0 版的.

在这一点上,使用 Qt 安装程序框架的人都知道,如果不进行自定义,您根本无法通过安装程序覆盖现有安装.这样做显然是为了解决在使用 Qt 框架时出现的一些问题.

但是,对于较小的、相对简单的项目,覆盖非常好,而且比事先手动运行维护工具要方便得多.

我正在寻找一种涉及自定义 UI + 组件脚本的解决方案,该脚本向目标目录页面添加一个按钮,允许用户执行

  1. 删除指定的目录(如果存在),或者
  2. 在该目录中运行维护工具.

最好能够在目标目录中运行维护工具,让它自动删除给定的包,但是我意识到这要求有点高.>

我已阅读本网站上有关解决同一问题的其他问题的答案,但没有一个解决方案能正常工作.我还想提一下,我已经启动并运行了一个组件脚本,但没有自定义 UI.

解决方案

我终于找到了一个可行的解决方案.

要做到这一点,您需要三件事:

  1. 一个组件脚本,
  2. 目标目录页面的自定义 UI,以及
  3. 自动点击卸载程序的控制器脚本.

我现在将逐字列出对我有用的内容(包括我的项目特定内容).我的组件叫做 Atlas4500 Tuner

config.xml:

packages/Atlas4500 Tuner/meta/package.xml:

自定义组件脚本packages/Atlas4500 Tuner/meta/installscript.qs:

var targetDirectoryPage = null;函数组件(){installer.gainAdminRights();component.loaded.connect(this, this.installerLoaded);}Component.prototype.createOperations = function(){//添加桌面和开始菜单快捷方式.组件.createOperations();component.addOperation("CreateShortcut","@TargetDir@/Atlas4500Tuner.exe","@DesktopDir@/Atlas4500 Tuner.lnk","workingDirectory=@TargetDir@");component.addOperation("CreateShortcut","@TargetDir@/Atlas4500Tuner.exe","@StartMenuDir@/Atlas4500 Tuner.lnk","workingDirectory=@TargetDir@");}Component.prototype.installerLoaded = function(){installer.setDefaultPageVisible(QInstaller.TargetDirectory, false);installer.addWizardPage(component, "TargetWidget", QInstaller.TargetDirectory);targetDirectoryPage = gui.pageWidgetByObjectName("DynamicTargetWidget");targetDirectoryPage.windowTitle = "选择安装目录";targetDirectoryPage.description.setText("请选择Atlas4500 Tuner的安装位置:");targetDirectoryPage.targetDirectory.textChanged.connect(this, this.targetDirectoryChanged);targetDirectoryPage.targetDirectory.setText(installer.value("TargetDir"));targetDirectoryPage.targetChooser.released.connect(this, this.targetChooserClicked);gui.pageById(QInstaller.ComponentSelection).entered.connect(this, this.componentSelectionPageEntered);}Component.prototype.targetChooserClicked = function(){var dir = QFileDialog.getExistingDirectory("", targetDirectoryPage.targetDirectory.text);targetDirectoryPage.targetDirectory.setText(dir);}Component.prototype.targetDirectoryChanged = function(){var dir = targetDirectoryPage.targetDirectory.text;if (installer.fileExists(dir) && installer.fileExists(dir + "/maintenancetool.exe")) {targetDirectoryPage.warning.setText("<p style="color: red">检测到现有安装并将被覆盖.</p>");}否则 if (installer.fileExists(dir)) {targetDirectoryPage.warning.setText("<p style="color: red">安装在现有目录中.卸载时会被擦除.</p>");}别的 {targetDirectoryPage.warning.setText("");}installer.setValue("TargetDir", dir);}Component.prototype.componentSelectionPageEntered = function(){var dir = installer.value("TargetDir");if (installer.fileExists(dir) && installer.fileExists(dir + "/maintenancetool.exe")) {installer.execute(dir + "/maintenancetool.exe", "--script=" + dir + "/scripts/auto_uninstall.qs");}}

自定义目标目录小部件packages/Atlas4500 Tuner/meta/targetwidget.ui:

packages/Atlas4500 Tuner/data/scripts/auto_uninstall.qs:

//控制器脚本传递给卸载程序以使其自动运行.//如果已经存在,则在安装过程中传递给维护工具//安装存在:<target dir>/maintenancetool.exe --script=<target dir>/scripts/auto_uninstall.qs.//这是必需的,这样用户就不必在中间看到/处理卸载程序//安装.功能控制器(){gui.clickButton(buttons.NextButton);gui.clickButton(buttons.NextButton);installer.uninstallationFinished.connect(this, this.uninstallationFinished);}Controller.prototype.uninstallationFinished = function(){gui.clickButton(buttons.NextButton);}Controller.prototype.FinishedPageCallback = function(){gui.clickButton(buttons.FinishButton);}

这里的想法是检测当前目录中是否有安装,如果有,使用控制器脚本运行该目录中的维护工具,只需点击它即可.

请注意,我将控制器脚本放在脚本目录中,该目录是实际组件数据的一部分.如果您有多个组件,您可能会做一些更简洁的事情,但这就是我正在使用的.

您应该能够自己复制这些文件,只需调整字符串即可使其工作.

This question is about version 2.0 of the Qt Installer Framework.

At this point, it is common knowledge for people using the Qt Installer Framework that, without customization, you simply can't overwrite an existing installation through your installer. This was apparently done to resolve some issues that occurred when this was done with the Qt framework.

However, for smaller, relatively simple projects, overwriting is perfectly fine and much more convenient than having to manually run the maintenance tool beforehand.

I am looking for a solution involving a custom UI + component script that adds a button to the target directory page that allows the user to either

  1. Remove the specified directory if it exists, or
  2. Run the maintenance tool in that directory.

It would be preferable to be able to run the maintenance tool in the target directory, having it automatically remove a given package, but I realize that that is asking for a little too much.

I have read answers to other questions on this site about solving the same problem, but none of the solutions work correctly. I would also like to mention that I have a component script up and running, but no custom UIs.

解决方案

I finally found a workable solution.

You need three things to pull this off:

  1. A component script,
  2. A custom UI for the target directory page, and
  3. A controller script that clicks through the uninstaller automatically.

I will now list verbatim what is working for me (with my project specific stuff). My component is called Atlas4500 Tuner

config.xml:

<?xml version="1.0" encoding="UTF-8"?>
<Installer>
    <Name>Atlas4500 Tuner</Name>
    <Version>1.0.0</Version>
    <Title>Atlas4500 Tuner Installer</Title>
    <Publisher>EF Johnson Technologies</Publisher>
    <StartMenuDir>EF Johnson</StartMenuDir>
    <TargetDir>C:Program Files (x86)EF JohnsonAtlas4500 Tuner</TargetDir>
</Installer>

packages/Atlas4500 Tuner/meta/package.xml:

<?xml version="1.0" encoding="UTF-8"?>
<Package>
    <DisplayName>Atlas4500Tuner</DisplayName>
    <Description>Install the Atlas4500 Tuner</Description>
    <Version>1.0.0</Version>
    <ReleaseDate></ReleaseDate>
    <Default>true</Default>
    <Required>true</Required>
    <Script>installscript.qs</Script>
    <UserInterfaces>
        <UserInterface>targetwidget.ui</UserInterface>
    </UserInterfaces>
</Package>

custom component script packages/Atlas4500 Tuner/meta/installscript.qs:

var targetDirectoryPage = null;

function Component() 
{
    installer.gainAdminRights();
    component.loaded.connect(this, this.installerLoaded);
}

Component.prototype.createOperations = function() 
{
    // Add the desktop and start menu shortcuts.
    component.createOperations();
    component.addOperation("CreateShortcut",
                           "@TargetDir@/Atlas4500Tuner.exe",
                           "@DesktopDir@/Atlas4500 Tuner.lnk",
                           "workingDirectory=@TargetDir@");

    component.addOperation("CreateShortcut",
                           "@TargetDir@/Atlas4500Tuner.exe",
                           "@StartMenuDir@/Atlas4500 Tuner.lnk",
                           "workingDirectory=@TargetDir@");
}

Component.prototype.installerLoaded = function()
{
    installer.setDefaultPageVisible(QInstaller.TargetDirectory, false);
    installer.addWizardPage(component, "TargetWidget", QInstaller.TargetDirectory);

    targetDirectoryPage = gui.pageWidgetByObjectName("DynamicTargetWidget");
    targetDirectoryPage.windowTitle = "Choose Installation Directory";
    targetDirectoryPage.description.setText("Please select where the Atlas4500 Tuner will be installed:");
    targetDirectoryPage.targetDirectory.textChanged.connect(this, this.targetDirectoryChanged);
    targetDirectoryPage.targetDirectory.setText(installer.value("TargetDir"));
    targetDirectoryPage.targetChooser.released.connect(this, this.targetChooserClicked);

    gui.pageById(QInstaller.ComponentSelection).entered.connect(this, this.componentSelectionPageEntered);
}

Component.prototype.targetChooserClicked = function()
{
    var dir = QFileDialog.getExistingDirectory("", targetDirectoryPage.targetDirectory.text);
    targetDirectoryPage.targetDirectory.setText(dir);
}

Component.prototype.targetDirectoryChanged = function()
{
    var dir = targetDirectoryPage.targetDirectory.text;
    if (installer.fileExists(dir) && installer.fileExists(dir + "/maintenancetool.exe")) {
        targetDirectoryPage.warning.setText("<p style="color: red">Existing installation detected and will be overwritten.</p>");
    }
    else if (installer.fileExists(dir)) {
        targetDirectoryPage.warning.setText("<p style="color: red">Installing in existing directory. It will be wiped on uninstallation.</p>");
    }
    else {
        targetDirectoryPage.warning.setText("");
    }
    installer.setValue("TargetDir", dir);
}

Component.prototype.componentSelectionPageEntered = function()
{
    var dir = installer.value("TargetDir");
    if (installer.fileExists(dir) && installer.fileExists(dir + "/maintenancetool.exe")) {
        installer.execute(dir + "/maintenancetool.exe", "--script=" + dir + "/scripts/auto_uninstall.qs");
    }
}

Custom target directory widget packages/Atlas4500 Tuner/meta/targetwidget.ui:

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>TargetWidget</class>
 <widget class="QWidget" name="TargetWidget">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>491</width>
    <height>190</height>
   </rect>
  </property>
  <property name="sizePolicy">
   <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
    <horstretch>0</horstretch>
    <verstretch>0</verstretch>
   </sizepolicy>
  </property>
  <property name="minimumSize">
   <size>
    <width>491</width>
    <height>190</height>
   </size>
  </property>
  <property name="windowTitle">
   <string>Form</string>
  </property>
  <layout class="QVBoxLayout" name="verticalLayout">
   <item>
    <widget class="QLabel" name="description">
     <property name="text">
      <string/>
     </property>
    </widget>
   </item>
   <item>
    <layout class="QHBoxLayout" name="horizontalLayout">
     <item>
      <widget class="QLineEdit" name="targetDirectory">
       <property name="readOnly">
        <bool>true</bool>
       </property>
      </widget>
     </item>
     <item>
      <widget class="QToolButton" name="targetChooser">
       <property name="sizePolicy">
        <sizepolicy hsizetype="Fixed" vsizetype="Preferred">
         <horstretch>0</horstretch>
         <verstretch>0</verstretch>
        </sizepolicy>
       </property>
       <property name="minimumSize">
        <size>
         <width>0</width>
         <height>0</height>
        </size>
       </property>
       <property name="text">
        <string>...</string>
       </property>
      </widget>
     </item>
    </layout>
   </item>
   <item>
    <layout class="QHBoxLayout" name="horizontalLayout_2">
     <property name="topMargin">
      <number>0</number>
     </property>
     <item>
      <widget class="QLabel" name="warning">
       <property name="enabled">
        <bool>true</bool>
       </property>
       <property name="text">
        <string>TextLabel</string>
       </property>
      </widget>
     </item>
     <item>
      <spacer name="horizontalSpacer">
       <property name="orientation">
        <enum>Qt::Horizontal</enum>
       </property>
       <property name="sizeHint" stdset="0">
        <size>
         <width>40</width>
         <height>20</height>
        </size>
       </property>
      </spacer>
     </item>
    </layout>
   </item>
   <item>
    <spacer name="verticalSpacer">
     <property name="orientation">
      <enum>Qt::Vertical</enum>
     </property>
     <property name="sizeHint" stdset="0">
      <size>
       <width>20</width>
       <height>122</height>
      </size>
     </property>
    </spacer>
   </item>
  </layout>
 </widget>
 <resources/>
 <connections/>
</ui>

packages/Atlas4500 Tuner/data/scripts/auto_uninstall.qs:

// Controller script to pass to the uninstaller to get it to run automatically.
// It's passed to the maintenance tool during installation if there is already an
// installation present with: <target dir>/maintenancetool.exe --script=<target dir>/scripts/auto_uninstall.qs.
// This is required so that the user doesn't have to see/deal with the uninstaller in the middle of
// an installation.

function Controller()
{
    gui.clickButton(buttons.NextButton);
    gui.clickButton(buttons.NextButton);

    installer.uninstallationFinished.connect(this, this.uninstallationFinished);
}

Controller.prototype.uninstallationFinished = function()
{
    gui.clickButton(buttons.NextButton);
}

Controller.prototype.FinishedPageCallback = function()
{
    gui.clickButton(buttons.FinishButton);
}

The idea here is to detect if the current directory has an installation in it or not, and, if it does, run the maintenance tool in that directory with a controller script that just clicks through it.

Note that I put the controller script in a scripts directory that is part of the actual component data. You could probably do something cleaner if you have multiple components, but this is what I am using.

You should be able to copy these files for yourself and just tweak the strings to make it work.

这篇关于Qt Installer Framework 不覆盖现有安装的解决方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆