Tasks: Migrate from tkinter to PySide6
Pre-Migration Tasks
-
Install PySide6 dependency
- Add
PySide6>=6.6.0to requirements (if exists) or install directly - Run
pip install PySide6 -
Validation:
python -c "from PySide6.QtWidgets import QApplication; print('OK')"
- Add
-
Backup current implementation
- Create git commit of current tkinter version
- Tag as
before-qt-migrationfor easy rollback -
Validation:
git log --oneline -1shows commit
Phase 1: LoginDialog Migration (Priority: Critical)
-
Create LoginDialog class structure
- Import PySide6 modules (QDialog, QVBoxLayout, QFormLayout, etc.)
- Define LoginDialog class inheriting from QDialog
- Move init parameters from LoginWindow
- Validation: Class instantiates without errors
-
Implement LoginDialog UI layout
- Create QVBoxLayout as main layout
- Add title QLabel
- Create QFormLayout for username/password fields
- Add QLineEdit widgets for username and password
- Set password field to QLineEdit.Password mode
- Validation: Dialog shows with all fields visible
-
Add checkbox row to LoginDialog
- Create QHBoxLayout for checkboxes
- Add "记住用户名" QCheckBox
- Add "记住密码" QCheckBox
- Set initial checked states from parameters
- Validation: Checkboxes appear and can be toggled
-
Add login button and error label
- Create QPushButton with text "登录"
- Connect to on_login slot
- Add QLabel for error messages (initially hidden)
- Validation: Button appears and is clickable
-
Apply LoginDialog styling
- Create QSS stylesheet for dialog
- Style title, labels, input fields, button
- Match colors from original design (#ffffff, #007AFF, #fafafa, etc.)
- Validation: Dialog matches design mockup
-
Implement password placeholder handling
- Check if saved_password_hash exists
- If yes, set placeholder text "••••••••" with gray color
- Bind textChanged signal to clear placeholder
- Validation: Placeholder shows and clears on typing
-
Implement authentication logic
- Move database connection code to on_login method
- Use pymysql exactly as in tkinter version
- Handle success: set result variables, accept dialog
- Handle failure: show error in error_label
- Validation: Login succeeds with valid credentials, fails with invalid
-
Implement dialog return values
- Store success, authenticated_user, password_hash as instance variables
- Provide getter methods or properties
- Return QDialog.Accepted on success, QDialog.Rejected on cancel
- Validation: Calling code can access all return values
-
Test LoginDialog on macOS
- Run application and verify dialog appears
- Verify all UI elements are visible (title, labels, inputs, button, checkboxes)
- Test typing in username field
- Test typing in password field (should be masked)
- Test login with valid credentials
- Test login with invalid credentials (should show error)
- Validation: ALL UI elements visible, login flow works
Phase 2: ImageGeneratorWindow Migration (Priority: High)
-
Create ImageGeneratorWindow class structure
- Define class inheriting from QMainWindow
- Move instance variables from ImageGeneratorApp
- Call load_config() in init
- Validation: Class instantiates, config loads
-
Create central widget and main layout
- Create QWidget as central widget
- Create QVBoxLayout as main layout
- Set central widget with setCentralWidget()
- Validation: Window shows with empty layout
-
Implement reference images section
- Create QGroupBox titled "参考图片"
- Add horizontal layout with "添加图片" button and count label
- Create QScrollArea for horizontal image preview
- Implement upload_images() method using QFileDialog
- Validation: Can upload images, preview appears
-
Implement image preview thumbnails
- For each uploaded image, create QLabel with scaled QPixmap
- Add delete button overlay or adjacent to each thumbnail
- Arrange horizontally in scroll area
- Implement delete_image() method
- Validation: Thumbnails appear, delete works
-
Implement prompt section
- Create QGroupBox titled "提示词"
- Add toolbar with favorite button, combo box, delete button
- Add QTextEdit for prompt input
- Set default text
- Validation: Section appears with all controls
-
Implement prompt favorites management
- Implement toggle_favorite() method
- Implement load_saved_prompt() slot for combo selection
- Implement delete_saved_prompt() method
- Update QComboBox when saved_prompts changes
- Validation: Can save, load, delete prompts
-
Implement settings section
- Create QGroupBox titled "生成设置"
- Add QLabel + QComboBox for aspect ratio
- Add QLabel + QComboBox for image size
- Set options and default values
- Validation: Settings section appears with dropdowns
-
Implement action buttons section
- Create QHBoxLayout for buttons
- Add "生成图片" QPushButton
- Add "下载图片" QPushButton (initially disabled)
- Add status QLabel
- Validation: Buttons appear with correct states
-
Implement preview section
- Create QGroupBox titled "预览"
- Add QLabel for image display
- Set placeholder text when no image
- Enable double-click to open system viewer
- Validation: Preview area appears with placeholder
-
Apply ImageGeneratorWindow styling
- Create comprehensive QSS stylesheet
- Style all sections, buttons, inputs
- Match original color scheme
- Validation: Window matches design, looks polished
-
Create ImageGenerationWorker thread
- Define class inheriting from QThread
- Add signals: finished(bytes), error(str), progress(str)
- Move image generation logic to run() method
- Use same Gemini API calls as tkinter version
- Validation: Thread instantiates, signals defined
-
Implement async image generation
- Create generate_image_async() method
- Instantiate ImageGenerationWorker
- Connect signals to slots (finished → display_image, error → show_error)
- Start worker thread
- Disable generate button during generation
- Validation: Image generation works without freezing UI
-
Implement image display
- In on_image_generated slot, receive image bytes
- Create QPixmap from bytes
- Scale to fit preview area
- Display in preview QLabel
- Enable download button
- Validation: Generated image displays correctly
-
Implement image download
- Use QFileDialog.getSaveFileName for save path
- Write image bytes to selected file
- Show success QMessageBox
- Validation: Can save generated images
-
Implement open in system viewer
- Handle double-click on preview QLabel
- Write temp file and open with QDesktopServices
- Validation: Double-click opens image in system viewer
-
Implement config save/load
- load_config() method (same logic as tkinter)
- save_config() method (same logic as tkinter)
- Handle API key, saved_prompts, db_config, last_user, password_hash
- Validation: Config persists across app restarts
Phase 3: Main Application Integration
-
Create main() function
- Create QApplication instance
- Show LoginDialog with exec()
- If accepted, create and show ImageGeneratorWindow
- Run app.exec()
- Handle dialog rejection (exit gracefully)
- Validation: Application flow works end-to-end
-
Update if name == "main" block
- Call main() function
- Keep database config loading logic
- Validation: Can run as standalone script
-
Remove old tkinter code
- Delete or comment out old LoginWindow class
- Delete or comment out old ImageGeneratorApp class
- Remove tkinter imports if no longer needed
- Keep utility functions (hash_password, DatabaseManager)
- Validation: No unused code remains
Phase 4: Testing & Polish (Priority: Medium)
-
macOS comprehensive testing
- Launch application
- LoginDialog: all elements visible
- LoginDialog: authentication works
- Main window: all sections visible
- Upload reference images
- Enter prompt
- Generate image
- Download image
- Save/load favorites
- Config persistence
- Validation: All features work on macOS
-
Windows comprehensive testing
- Launch application
- Verify native Windows look
- Test all features (same as macOS checklist)
- Check high-DPI scaling
- Validation: All features work on Windows
-
Cross-platform consistency check
- Compare screenshots from macOS and Windows
- Verify consistent layout and sizing
- Check font rendering
- Validation: UI looks good on both platforms
-
Performance testing
- Test with 10+ reference images
- Test with long prompts
- Test rapid UI interactions
- Check memory usage
- Validation: No lag, no memory leaks
-
Error handling testing
- Test with invalid API key
- Test with no network connection
- Test with corrupted image files
- Test with invalid database credentials
- Validation: Graceful error messages, no crashes
-
UI polish and refinements
- Adjust spacing and padding if needed
- Fine-tune button sizes
- Improve loading indicators
- Add tooltips to buttons
- Validation: UI feels polished and professional
-
Documentation updates
- Update README with PySide6 dependency
- Document installation steps
- Note Qt-specific features
- Validation: Documentation is accurate
Dependencies
- Tasks 1-2: Must complete before any migration work
- Tasks 3-11: LoginDialog (can work independently)
- Tasks 12-27: ImageGeneratorWindow (depends on LoginDialog being tested)
- Tasks 28-30: Integration (depends on both windows complete)
- Tasks 31-37: Testing and polish (depends on integration complete)
Estimated Time
- Phase 1 (LoginDialog): 2-3 hours
- Phase 2 (ImageGeneratorWindow): 4-6 hours
- Phase 3 (Integration): 1 hour
- Phase 4 (Testing & Polish): 1-2 hours
- Total: 8-12 hours
Notes
- Focus on getting LoginDialog working first to validate Qt works on macOS
- Keep DatabaseManager and hash_password unchanged (they work fine)
- Preserve all existing functionality - no feature removals
- Use QSS for styling consistently
- Use QThread for all async operations
- Test frequently on macOS to catch issues early