2011-01-13 34 views
5

Có ai biết thư viện C++ sẽ cung cấp giao diện tương tác dựa trên văn bản không? Tôi muốn tạo ra hai phiên bản của một ứng dụng; một chương trình dựa trên giao diện điều khiển sẽ thực hiện bất kỳ hành động nào được đưa ra trên dòng lệnh hoặc tương tác tại bàn điều khiển cũng như một chương trình dựa trên GUI (Mac Cocoa và Windows MFC). Cả hai phiên bản sẽ chia sẻ một chương trình phụ trợ C++ phổ biến.Nền tảng chéo, Giao diện dựa trên văn bản tương tác với hoàn thành lệnh

Đối với chương trình dựa trên bảng điều khiển, tôi muốn có khả năng lịch sử tương tự như readline (mà tôi không thể sử dụng vì ứng dụng này sẽ là nguồn đóng) với hoàn thành lệnh (ví dụ: Tab được kích hoạt).

Có thể có điều gì đó như thế này đã có sẵn?

Trả lời

1

Cập nhật: Tôi chưa tìm thấy giải pháp thỏa đáng (đa nền tảng) cho tùy chọn lịch sử/hoàn thành, vì vậy tôi đã bỏ qua điều đó, nhưng tôi muốn cập nhật câu hỏi này với cách tôi đã triển khai một lớp tương tác đơn giản. Giao diện này sẽ không dành cho người dùng chính thống nhưng tôi thấy nó rất tiện dụng để kiểm tra mã của tôi trong khi triển khai. Dưới đây là việc thực hiện ban đầu mà có thể giúp đỡ người khác ra (lưu ý rằng mã này tham chiếu các phương pháp và các loại tôi đã không được công bố, như vậy sẽ không biên dịch ra khỏi hộp)

Interact.h:

#ifndef INTERACT_H 
#define INTERACT_H 

class Interact; 
class InteractCommand; 
typedef void (Interact::*PF_FUNC)(const InteractCommand &command, const StringVector &args); 

struct InteractCommand 
{ 
    const char *command; 
    const char *argDesc; 
    const char *desc; 
    PF_FUNC func; 
}; 

class Interact 
{ 
private: 
    static Log m_log; 
    static InteractCommand m_commands[]; 
    static unsigned m_numCommands; 

    bool m_stop; 
    Database &m_database; 
    StringVector &m_dirs; 

public: 
    Interact(Database &database, StringVector &dirs); 
    ~Interact(); 

    /** 
    * Main 'interact' loop. 
    * 
    * @return true if the loop exitted normally, else false if an error occurred. 
    */ 
    bool interact(); 

private: 
    // Functions 
#define DEFFUNC(f) void FUNC_##f(const InteractCommand &command, const StringVector &args) 
    DEFFUNC(database); 
    DEFFUNC(dirs); 
    DEFFUNC(exit); 
    DEFFUNC(help); 
#undef DEFFUNC 


    /** 
    * Print usage information for the specified command. 
    * 
    * @param command The command to print usage for. 
    */ 
    static void usage(const InteractCommand &command); 

    static void describeCommand(string &dest, const InteractCommand &command); 
}; 

#endif // INTERACT_H 

Tương tác .cpp:

#include "Interact.h" 

Log Interact::m_log("Interact"); 

#define IFUNC(f) &Interact::FUNC_##f 
InteractCommand Interact::m_commands[] = 
{ 
    { "database", "<file>|close", "Use database <file> or close opened database", IFUNC(database) }, 
    { "dirs", "dir[,dir...]", "Set the directories to scan", IFUNC(dirs) }, 
    { "exit", 0, "Exit", IFUNC(exit) }, 
    { "help", 0, "Print help", IFUNC(help) } 
}; 
#undef IFUNC 

unsigned Interact::m_numCommands = sizeof(m_commands)/sizeof(m_commands[0]); 

Interact::Interact(MusicDatabase &database, StringVector &dirs) : 
    m_stop(false), 
    m_database(database), 
    m_dirs(dirs) 
{ 
} 

Interact::~Interact() 
{ 
} 

bool Interact::interact() 
{ 
    string line; 
    StringVector args; 
    unsigned i; 

    m_stop = false; 
    while (!m_stop) 
    { 
     args.clear(); 
     cout << "> "; 
     if (!getline(cin, line) || cin.eof()) 
      break; 
     else if (cin.fail()) 
      return false; 

     if (!Util::splitString(line, " ", args) || args.size() == 0) 
      continue; 

     for (i = 0; i < m_numCommands; i++) 
      if (strncasecmp(args[0].c_str(), m_commands[i].command, args[0].length()) == 0) 
       break; 
     if (i < m_numCommands) 
      (this->*m_commands[i].func)(m_commands[i], args); 
     else 
      cout << "Unknown command '" << args[0] << "'" << endl; 
    } 
    return true; 
} 

void Interact::FUNC_database(const InteractCommand &command, const StringVector &args) 
{ 
    if (args.size() != 2) 
    { 
     usage(command); 
     return; 
    } 

    if (args[1] == "close") 
    { 
     if (m_database.opened()) 
      m_database.close(); 
     else 
      cout << "Database is not open" << endl; 
    } 
    else 
    { 
     if (!m_database.open(args[1])) 
     { 
      cout << "Failed to open database" << endl; 
     } 
    } 
} 

void Interact::FUNC_dirs(const InteractCommand &command, const StringVector &args) 
{ 
    if (args.size() == 1) 
    { 
     usage(command); 
     return; 
    } 
    // TODO 

} 

void Interact::FUNC_exit(const InteractCommand &command, const StringVector &args) 
{ 
    m_stop = true; 
} 

void Interact::FUNC_help(const InteractCommand &command, const StringVector &/*args*/) 
{ 
    string descr; 
    for (unsigned i = 0; i < m_numCommands; i++) 
    { 
     describeCommand(descr, m_commands[i]); 
     cout << descr << endl; 
    } 
} 

void Interact::usage(const InteractCommand &command) 
{ 
    string descr; 
    describeCommand(descr, command); 
    cout << "usage: " << endl; 
    cout << descr << endl; 
} 

void Interact::describeCommand(string &dest, const InteractCommand &command) 
{ 
    dest.clear(); 
    string cmdStr = command.command; 
    if (command.argDesc != 0) 
    { 
     cmdStr += " "; 
     cmdStr += command.argDesc; 
    } 
    Util::format(dest, " %-30s%s", cmdStr.c_str(), command.desc); 
} 
2

Trong không theo thứ tự đặc biệt, (tôi đã sử dụng ai trong số họ,), bạn nên có một cái nhìn tại địa chỉ:

Nếu không ai trong số những người có ưa thích của bạn, bạn có một khả năng khác, và có lẽ nó thậm chí có thể được ưa thích. Viết backend của bạn như một daemon và có giao diện người dùng là một chương trình câm liên lạc với chương trình phụ trợ thông qua bất kỳ hình thức liên lạc quá trình liên thông nào. Sau đó, bạn có thể sử dụng bất kỳ thư viện GPL nào cho giao diện người dùng của mình mà không gặp bất kỳ sự cố nào khi bạn có thể phát hành giao diện người dùng làm nguồn mở. Tất nhiên điều này sẽ làm lộ giao thức truyền thông giữa giao diện người dùng và phụ trợ, vì vậy bạn phải chắc chắn rằng điều đó có thể xảy ra và dĩ nhiên khả năng người khác có thể cảm thấy cần phải thực hiện các tùy chỉnh cho giao diện người dùng của bạn và thậm chí có thể tự làm. Tuy nhiên, giả sử rằng giá trị của bạn nằm trong chương trình phụ trợ, điều này không nên đặt ra một vấn đề cụ thể. Và nó thậm chí có thể được coi là một cộng, nó sẽ cho phép bất cứ ai có một ý tưởng sáng để sử dụng phần mềm của bạn theo những cách mới và bất ngờ chỉ làm tăng sự phổ biến của phần mềm của bạn.

+0

Rất cám ơn các đề xuất. Tất cả các thư viện này chỉ dành cho UNIX/LINUX và không dành cho Windows, không đáp ứng yêu cầu đa nền tảng. Tại thời điểm này tôi đã viết trình thông dịch lệnh đơn giản của riêng mình và đã bỏ qua khía cạnh lịch sử/hoàn thành lệnh. TBH này có lẽ sẽ đủ để giữ cho tôi hạnh phúc trong một thời gian. – trojanfoe

Các vấn đề liên quan