【问题标题】:How to "refresh" TListBox?如何“刷新” TListBox?
【发布时间】:2021-08-03 00:31:45
【问题描述】:

我正在创建一个显示帐单号码的应用程序,就像您在麦当劳看到的那样。 POS 系统将账单号码发送到我的应用程序,这些号码显示在名为“ListBoxPrep”的 TListBox 中。然后,当 POS 系统向我的应用发送要删除的账单编号时,我的应用会从“ListBoxPrep”中删除它并将其添加到“ListBoxReady”。 POS 和我的应用程序之间的每次通信都是通过 TCP 连接完成的,我对此没有任何问题。

我面临的问题是,即使在通过“pItem->Free();”删除它之后,我仍然看到该数字仍保留在“ListBoxPrep”中。 “pItem”是TListBoxItem 的指针。我希望我的应用程序从 POS 接收到“删除信号”后数字消失,尤其是在没有用户交互(例如单击面板等)的情况下。我想使用 TTimer,但我不知道如何使“ListBoxPrep”刷新本身。你有什么想法吗?任何建议将不胜感激。我正在使用 RAD Studio 10.4。

在我的应用收到来自 POS 的“删除信号”后,我仍然看到右侧的数字。他们应该消失。

只要我单击“ListBoxPrep”,数字就会消失。

void __fastcall TForm1::IdTCPServerExecute(TIdContext *AContext)
{
    //We receive data: POS --> Screen(PC)
    String sentDataFromPOS = AContext->Connection->Socket->ReadLn();

    if(sentDataFromPOS .IsEmpty())
    {
        ShowMessage("Data sent from POS is empty!");
        return;
    }

    // 1. Find an order number to move to the right (prep -> ready)
    int indexOrderToRemove = ListBoxPrep->Items->IndexOf(sentDataFromPOS);

    // 2. Add the order number to the "Ready list"
    addNumberToReady(sentDataFromPOS);

    // 3. Remove the order from the "Prep list"
    ListBoxPrep->BeginUpdate();
    TListBoxItem* pItem = ListBoxPrep->ItemByIndex(indexOrderToRemove);
    pItem->Free(); // HERE I have a problem

    // test: To refresh the screen
    LayoutLeft->Visible = false;
    LayoutLeft->Visible = true;

    /*
    ListBoxPrep->Enabled = false;
    ListBoxPrep->Visible = false;
    ListBoxPrep->Enabled = true;
    ListBoxPrep->Visible = true;
    ListBoxPrep->Repaint();
    */
    ListBoxPrep->EndUpdate();
}

【问题讨论】:

  • sentDataFromKitchensentDataFromPOS 有什么关系?
  • 哦,实际上sentDataFromKitchensentDataFromPOS。我错误地输入了sentDataFromKitchen,对不起。我已经编辑了代码。

标签: firemonkey c++builder rad-studio


【解决方案1】:

TIdTCPServer 是一个多线程组件。它的OnExecute 事件在工作线程的上下文中被调用。因此,在访问 UI 控件时,它必须与主 UI 线程同步(这也适用于 ShowMessage(),顺便说一句)。为此,您可以使用 RTL 的 TThread::Synchronize()(同步)或 TThread::Queue()(异步)方法。

另外,你不应该直接Free()'ing TListBoxItem 对象。您有所需项目的索引,您可以使用ListBoxPrep->Items->Delete()

如果您使用的是clang-based compilers 之一,请尝试类似这样的操作:

void __fastcall TForm1::IdTCPServerExecute(TIdContext *AContext)
{
    //We receive data: POS --> Screen(PC)
    String sentDataFromPOS = AContext->Connection->Socket->ReadLn();

    if (sentDataFromPOS.IsEmpty())
    {
        TThread::Synchronize(nullptr,
            [](){ ShowMessage("Data sent from POS is empty!"); }
        );
        return;
    }

    TThread::Queue(nullptr, // or Synchronize(), your choice...
        [=, this](){ this->orderIsReady(sentDataFromPOS); }
    );
}

void __fastcall TForm1::orderIsReady(String orderNumber)
{
    // 1. Find an order number to move to the right (prep -> ready)
    int indexOrderToRemove = ListBoxPrep->Items->IndexOf(orderNumber);

    // 2. Add the order number to the "Ready list"
    addNumberToReady(orderNumber);

    // 3. Remove the order from the "Prep list"
    if (indexOrderToRemove != -1)
        ListBoxPrep->Items->Delete(indexOrderToRemove);
}

另一方面,如果您使用的是"classic" Borland compiler,请尝试以下操作:

struct orderHelper
{
    String orderNumber;

    orderHelper(const String &orderNumber)
        : orderNumber(orderNumber)
    {
    }

    void __fastcall orderIsReady()
    {
        Form1->orderIsReady(orderNumber);
    }
};

void __fastcall TForm1::orderIsEmpty()
{
    ShowMessage("Data sent from POS is empty!");
}

void __fastcall TForm1::IdTCPServerExecute(TIdContext *AContext)
{
    //We receive data: POS --> Screen(PC)

    String sentDataFromPOS = AContext->Connection->Socket->ReadLn();

    if (sentDataFromPOS.IsEmpty())
    {
        TThread::Synchronize(NULL, &orderIsEmpty);
        return;
    }

    orderHelper helper(sentDataFromPOS);
    TThread::Synchronize(NULL, &(helper.orderIsReady));
}

void __fastcall TForm1::orderIsReady(String orderNumber)
{
    // 1. Find an order number to move to the right (prep -> ready)
    int indexOrderToRemove = ListBoxPrep->Items->IndexOf(orderNumber);

    // 2. Add the order number to the "Ready list"
    addNumberToReady(orderNumber);

    // 3. Remove the order from the "Prep list"
    if (indexOrderToRemove != -1)
        ListBoxPrep->Items->Delete(indexOrderToRemove);
}

或者这个:

struct orderHelper
{
    String orderNumber;

    orderHelper(const String &orderNumber)
        : orderNumber(orderNumber)
    {
    }

    void __fastcall orderIsReady()
    {
        try {
            Form1->orderIsReady(orderNumber);
        } __finally {
            delete this;
        }
    }
};

void __fastcall TForm1::orderIsEmpty()
{
    ShowMessage("Data sent from POS is empty!");
}

void __fastcall TForm1::IdTCPServerExecute(TIdContext *AContext)
{
    //We receive data: POS --> Screen(PC)

    String sentDataFromPOS = AContext->Connection->Socket->ReadLn();

    if (sentDataFromPOS.IsEmpty())
    {
        TThread::Synchronize(NULL, &orderIsEmpty);
        return;
    }

    orderHelper *helper = new orderHelper(sentDataFromPOS);
    TThread::Queue(NULL, &(helper->orderIsReady));
}

void __fastcall TForm1::orderIsReady(String orderNumber)
{
    // 1. Find an order number to move to the right (prep -> ready)
    int indexOrderToRemove = ListBoxPrep->Items->IndexOf(orderNumber);

    // 2. Add the order number to the "Ready list"
    addNumberToReady(orderNumber);

    // 3. Remove the order from the "Prep list"
    if (indexOrderToRemove != -1)
        ListBoxPrep->Items->Delete(indexOrderToRemove);
}

【讨论】:

  • 您的第一个建议效果很好!非常感谢您的帮助!
【解决方案2】:

我修改了IdTCPServerExecute 中的一些代码以消除一些编译错误。这是运行良好的代码。再次感谢Remy Lebeau

void __fastcall TForm1::IdTCPServerExecute(TIdContext *AContext)
{
    //We receive data: POS --> Screen(PC)
    String sentDataFromPos = AContext->Connection->Socket->ReadLn();

    // test
    //sentDataFromPos = "";

    if(sentDataFromPos.IsEmpty())
    {
        TThread::Synchronize(nullptr,
            [=](){ ShowMessage("Data sent from POS is empty!"); }
        );

        return;
    }

    TThread::Synchronize(nullptr, 
// Queue doesn't make the numbers disappear. It doesn't display them at right side either .
        [&, this]()
        {
            this->orderIsReady(sentDataFromPos);
        }
    );
}
//---------------------------------------------------------------------------
void __fastcall TForm1::orderIsReady(String orderNumber)
{
    // 1. Find an order to move to the right (prep -> ready)
    int indexOrderToRemove = ListBoxPrep->Items->IndexOf(orderNumber);

    // 2. Add an order of the same order number to the "Ready list"
    addNumberToReady(orderNumber);

    // 3. Remove the order from the "Prep list"
    if(indexOrderToRemove != -1)
    {
        ListBoxPrep->Items->Delete(indexOrderToRemove);
    }
}

【讨论】:

  • TThread::Synchronize()TThread::Queue()之间的唯一区别在于Synchronize()等待指定函数退出,其中Queue()在指定函数运行时立即退出在后台。它们都在主 UI 线程内部使用相同的队列,因此 TThread::Synchronize(nullptr, [&, this]() { this->orderIsReady(sentDataFromPos); });TThread::Queue(nullptr, [=, this]() { this->orderIsReady(sentDataFromPos); } ); 之间应该没有 实际 区别,除了第一个会阻塞 OnExecute 而第二个不会。
猜你喜欢
  • 1970-01-01
  • 2013-06-17
  • 2017-05-29
  • 2017-10-12
  • 2017-10-09
  • 1970-01-01
  • 2014-04-23
  • 2023-01-20
  • 2013-03-20
相关资源
最近更新 更多